Let enhmetafiles reuse gdi handles. This works by a dc 'registering'
[wine] / dlls / gdi / enhmfdrv / objects.c
1 /*
2  * Enhanced MetaFile objects
3  *
4  * Copyright 1999 Huw D M Davies
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
25 #include "bitmap.h"
26 #include "enhmfdrv/enhmetafiledrv.h"
27 #include "wine/debug.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
30
31
32 /******************************************************************
33  *         EMFDRV_AddHandle
34  */
35 static UINT EMFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
36 {
37     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
38     UINT index;
39
40     for(index = 0; index < physDev->handles_size; index++)
41         if(physDev->handles[index] == 0) break;
42     if(index == physDev->handles_size) {
43         physDev->handles_size += HANDLE_LIST_INC;
44         physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
45                                        physDev->handles,
46                                        physDev->handles_size * sizeof(physDev->handles[0]));
47     }
48     physDev->handles[index] = obj;
49
50     physDev->cur_handles++;
51     if(physDev->cur_handles > physDev->emh->nHandles)
52         physDev->emh->nHandles++;
53
54     return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
55 }
56
57 /******************************************************************
58  *         EMFDRV_FindObject
59  */
60 static UINT EMFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
61 {
62     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*) dev;
63     UINT index;
64
65     for(index = 0; index < physDev->handles_size; index++)
66         if(physDev->handles[index] == obj) break;
67
68     if(index == physDev->handles_size) return 0;
69
70     return index + 1;
71 }
72
73
74 /******************************************************************
75  *         EMFDRV_DeleteObject
76  */
77 BOOL EMFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
78 {
79     EMRDELETEOBJECT emr;
80     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*) dev;
81     UINT index;
82     BOOL ret = TRUE;
83
84     if(!(index = EMFDRV_FindObject(dev, obj))) return 0;
85
86     emr.emr.iType = EMR_DELETEOBJECT;
87     emr.emr.nSize = sizeof(emr);
88     emr.ihObject = index;
89
90     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
91         ret = FALSE;
92
93     physDev->handles[index - 1] = 0;
94     physDev->cur_handles--;
95     return ret;
96 }
97
98   
99 /***********************************************************************
100  *           EMFDRV_SelectBitmap
101  */
102 HBITMAP EMFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
103 {
104     return 0;
105 }
106
107
108 /***********************************************************************
109  *           EMFDRV_CreateBrushIndirect
110  */
111 DWORD EMFDRV_CreateBrushIndirect( PHYSDEV dev, HBRUSH hBrush )
112 {
113     DWORD index = 0;
114     LOGBRUSH logbrush;
115
116     if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return 0;
117
118     switch (logbrush.lbStyle) {
119     case BS_SOLID:
120     case BS_HATCHED:
121     case BS_NULL:
122       {
123         EMRCREATEBRUSHINDIRECT emr;
124         emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
125         emr.emr.nSize = sizeof(emr);
126         emr.ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
127         emr.lb = logbrush;
128
129         if(!EMFDRV_WriteRecord( dev, &emr.emr ))
130             index = 0;
131       }
132       break;
133     case BS_DIBPATTERN:
134       {
135         EMRCREATEDIBPATTERNBRUSHPT *emr;
136         DWORD bmSize, biSize, size;
137         BITMAPINFO *info = GlobalLock16(logbrush.lbHatch);
138
139         if (info->bmiHeader.biCompression)
140             bmSize = info->bmiHeader.biSizeImage;
141         else
142             bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
143                                           info->bmiHeader.biHeight,
144                                           info->bmiHeader.biBitCount);
145         biSize = DIB_BitmapInfoSize(info, LOWORD(logbrush.lbColor));
146         size = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize + bmSize;
147         emr = HeapAlloc( GetProcessHeap(), 0, size );
148         if(!emr) break;
149         emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
150         emr->emr.nSize = size;
151         emr->ihBrush = index = EMFDRV_AddHandle( dev, hBrush );
152         emr->iUsage = LOWORD(logbrush.lbColor);
153         emr->offBmi = sizeof(EMRCREATEDIBPATTERNBRUSHPT);
154         emr->cbBmi = biSize;
155         emr->offBits = sizeof(EMRCREATEDIBPATTERNBRUSHPT) + biSize;
156         emr->cbBits = bmSize;
157         memcpy((char *)emr + sizeof(EMRCREATEDIBPATTERNBRUSHPT), info,
158                biSize + bmSize );
159
160         if(!EMFDRV_WriteRecord( dev, &emr->emr ))
161             index = 0;
162         HeapFree( GetProcessHeap(), 0, emr );
163         GlobalUnlock16(logbrush.lbHatch);
164       }
165       break;
166
167     case BS_PATTERN:
168         FIXME("Unsupported style %x\n",
169               logbrush.lbStyle);
170         break;
171     default:
172         FIXME("Unknown style %x\n", logbrush.lbStyle);
173         break;
174     }
175     return index;
176 }
177
178
179 /***********************************************************************
180  *           EMFDRV_SelectBrush
181  */
182 HBRUSH EMFDRV_SelectBrush(PHYSDEV dev, HBRUSH hBrush )
183 {
184     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
185     EMRSELECTOBJECT emr;
186     DWORD index;
187     int i;
188
189     /* If the object is a stock brush object, do not need to create it.
190      * See definitions in  wingdi.h for range of stock brushes.
191      * We do however have to handle setting the higher order bit to
192      * designate that this is a stock object.
193      */
194     for (i = WHITE_BRUSH; i <= NULL_BRUSH; i++)
195     {
196         if (hBrush == GetStockObject(i))
197         {
198             index = i | 0x80000000;
199             goto found;
200         }
201     }
202     if((index = EMFDRV_FindObject(dev, hBrush)) != 0)
203         goto found;
204
205     if (!(index = EMFDRV_CreateBrushIndirect(dev, hBrush ))) return 0;
206     GDI_hdc_using_object(hBrush, physDev->hdc);
207
208  found:
209     emr.emr.iType = EMR_SELECTOBJECT;
210     emr.emr.nSize = sizeof(emr);
211     emr.ihObject = index;
212     return EMFDRV_WriteRecord( dev, &emr.emr ) ? hBrush : 0;
213 }
214
215
216 /******************************************************************
217  *         EMFDRV_CreateFontIndirect
218  */
219 static BOOL EMFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont )
220 {
221     DWORD index = 0;
222     EMREXTCREATEFONTINDIRECTW emr;
223     int i;
224
225     if (!GetObjectW( hFont, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return 0;
226
227     emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
228     emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
229     emr.ihFont = index = EMFDRV_AddHandle( dev, hFont );
230     emr.elfw.elfFullName[0] = '\0';
231     emr.elfw.elfStyle[0]    = '\0';
232     emr.elfw.elfVersion     = 0;
233     emr.elfw.elfStyleSize   = 0;
234     emr.elfw.elfMatch       = 0;
235     emr.elfw.elfReserved    = 0;
236     for(i = 0; i < ELF_VENDOR_SIZE; i++)
237         emr.elfw.elfVendorId[i] = 0;
238     emr.elfw.elfCulture                 = PAN_CULTURE_LATIN;
239     emr.elfw.elfPanose.bFamilyType      = PAN_NO_FIT;
240     emr.elfw.elfPanose.bSerifStyle      = PAN_NO_FIT;
241     emr.elfw.elfPanose.bWeight          = PAN_NO_FIT;
242     emr.elfw.elfPanose.bProportion      = PAN_NO_FIT;
243     emr.elfw.elfPanose.bContrast        = PAN_NO_FIT;
244     emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT;
245     emr.elfw.elfPanose.bArmStyle        = PAN_NO_FIT;
246     emr.elfw.elfPanose.bLetterform      = PAN_NO_FIT;
247     emr.elfw.elfPanose.bMidline         = PAN_NO_FIT;
248     emr.elfw.elfPanose.bXHeight         = PAN_NO_FIT;
249
250     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
251         index = 0;
252     return index;
253 }
254
255
256 /***********************************************************************
257  *           EMFDRV_SelectFont
258  */
259 HFONT EMFDRV_SelectFont( PHYSDEV dev, HFONT hFont )
260 {
261     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
262     EMRSELECTOBJECT emr;
263     DWORD index;
264     int i;
265
266     /* If the object is a stock font object, do not need to create it.
267      * See definitions in  wingdi.h for range of stock fonts.
268      * We do however have to handle setting the higher order bit to
269      * designate that this is a stock object.
270      */
271
272     for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
273     {
274         if (i != DEFAULT_PALETTE && hFont == GetStockObject(i))
275         {
276             index = i | 0x80000000;
277             goto found;
278         }
279     }
280
281     if((index = EMFDRV_FindObject(dev, hFont)) != 0)
282         goto found;
283
284     if (!(index = EMFDRV_CreateFontIndirect(dev, hFont ))) return HGDI_ERROR;
285     GDI_hdc_using_object(hFont, physDev->hdc);
286
287  found:
288     emr.emr.iType = EMR_SELECTOBJECT;
289     emr.emr.nSize = sizeof(emr);
290     emr.ihObject = index;
291     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
292         return HGDI_ERROR;
293     return 0;
294 }
295
296
297
298 /******************************************************************
299  *         EMFDRV_CreatePenIndirect
300  */
301 static HPEN EMFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen )
302 {
303     EMRCREATEPEN emr;
304     DWORD index = 0;
305
306     if (!GetObjectA( hPen, sizeof(emr.lopn), &emr.lopn )) return 0;
307
308     emr.emr.iType = EMR_CREATEPEN;
309     emr.emr.nSize = sizeof(emr);
310     emr.ihPen = index = EMFDRV_AddHandle( dev, hPen );
311
312     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
313         index = 0;
314     return (HPEN)index;
315 }
316
317 /******************************************************************
318  *         EMFDRV_SelectPen
319  */
320 HPEN EMFDRV_SelectPen(PHYSDEV dev, HPEN hPen )
321 {
322     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*)dev;
323     EMRSELECTOBJECT emr;
324     DWORD index;
325     int i;
326
327     /* If the object is a stock pen object, do not need to create it.
328      * See definitions in  wingdi.h for range of stock pens.
329      * We do however have to handle setting the higher order bit to
330      * designate that this is a stock object.
331      */
332
333     for (i = WHITE_PEN; i <= NULL_PEN; i++)
334     {
335         if (hPen == GetStockObject(i))
336         {
337             index = i | 0x80000000;
338             goto found;
339         }
340     }
341     if((index = EMFDRV_FindObject(dev, hPen)) != 0)
342         goto found;
343
344     if (!(index = (DWORD)EMFDRV_CreatePenIndirect(dev, hPen ))) return 0;
345     GDI_hdc_using_object(hPen, physDev->hdc);
346
347  found:
348     emr.emr.iType = EMR_SELECTOBJECT;
349     emr.emr.nSize = sizeof(emr);
350     emr.ihObject = index;
351     return EMFDRV_WriteRecord( dev, &emr.emr ) ? hPen : 0;
352 }
353
354
355 /******************************************************************
356  *         EMFDRV_GdiComment
357  */
358 BOOL EMFDRV_GdiComment(PHYSDEV dev, UINT bytes, CONST BYTE *buffer)
359 {
360     EMRGDICOMMENT *emr;
361     UINT total, rounded_size;
362     BOOL ret;
363
364     rounded_size = (bytes+3) & ~3;
365     total = offsetof(EMRGDICOMMENT,Data) + rounded_size;
366
367     emr = HeapAlloc(GetProcessHeap(), 0, total);
368     emr->emr.iType = EMR_GDICOMMENT;
369     emr->emr.nSize = total;
370     emr->cbData = bytes;
371     memset(&emr->Data[bytes], 0, rounded_size - bytes);
372     memcpy(&emr->Data[0], buffer, bytes);
373
374     ret = EMFDRV_WriteRecord( dev, &emr->emr );
375
376     HeapFree(GetProcessHeap(), 0, emr);
377
378     return ret;
379 }