opengl32: Avoid generating a wrapper for internal functions when we can call the...
[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 "wownt32.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_FindObject
63  */
64 static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
65 {
66     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
67     INT16 index;
68
69     for(index = 0; index < physDev->handles_size; index++)
70         if(physDev->handles[index] == obj) break;
71
72     if(index == physDev->handles_size) return -1;
73
74     return index ;
75 }
76
77
78 /******************************************************************
79  *         MFDRV_DeleteObject
80  */
81 BOOL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
82 {   
83     METARECORD mr;
84     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
85     INT16 index;
86     BOOL ret = TRUE;
87
88     index = MFDRV_FindObject(dev, obj);
89     if( index < 0 )
90         return 0;
91
92     mr.rdSize = sizeof mr / 2;
93     mr.rdFunction = META_DELETEOBJECT;
94     mr.rdParm[0] = index;
95
96     if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
97         ret = FALSE;
98
99     physDev->handles[index] = 0;
100     physDev->cur_handles--;
101     return ret;
102 }
103
104
105 /***********************************************************************
106  *           MFDRV_SelectObject
107  */
108 static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
109 {
110     METARECORD mr;
111
112     mr.rdSize = sizeof mr / 2;
113     mr.rdFunction = META_SELECTOBJECT;
114     mr.rdParm[0] = index;
115
116     return MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 );
117 }
118
119
120 /***********************************************************************
121  *           MFDRV_SelectBitmap
122  */
123 HBITMAP MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
124 {
125     return 0;
126 }
127
128 /***********************************************************************
129  * Internal helper for MFDRV_CreateBrushIndirect():
130  * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
131  */
132 static inline void MFDRV_PadTo32(LPBYTE lpRows, int height, int width)
133 {
134     int bytes16 = 2 * ((width + 15) / 16);
135     int bytes32 = 4 * ((width + 31) / 32);
136     LPBYTE lpSrc, lpDst;
137     int i;
138
139     if (!height)
140         return;
141
142     height = abs(height) - 1;
143     lpSrc = lpRows + height * bytes16;
144     lpDst = lpRows + height * bytes32;
145
146     /* Note that we work backwards so we can re-pad in place */
147     while (height >= 0)
148     {
149         for (i = bytes32; i > bytes16; i--)
150             lpDst[i - 1] = 0; /* Zero the padding bytes */
151         for (; i > 0; i--)
152             lpDst[i - 1] = lpSrc[i - 1]; /* Move image bytes into alignment */
153         lpSrc -= bytes16;
154         lpDst -= bytes32;
155         height--;
156     }
157 }
158
159 /***********************************************************************
160  * Internal helper for MFDRV_CreateBrushIndirect():
161  * Reverse order of bitmap rows in going from BMP to DIB.
162  */
163 static inline void MFDRV_Reverse(LPBYTE lpRows, int height, int width)
164 {
165     int bytes = 4 * ((width + 31) / 32);
166     LPBYTE lpSrc, lpDst;
167     BYTE temp;
168     int i;
169
170     if (!height)
171         return;
172
173     lpSrc = lpRows;
174     lpDst = lpRows + (height-1) * bytes;
175     height = height/2;
176
177     while (height > 0)
178     {
179         for (i = 0; i < bytes; i++)
180         {
181             temp = lpDst[i];
182             lpDst[i] = lpSrc[i];
183             lpSrc[i] = temp;
184         }
185         lpSrc += bytes;
186         lpDst -= bytes;
187         height--;
188     }
189 }
190
191 /******************************************************************
192  *         MFDRV_CreateBrushIndirect
193  */
194
195 INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
196 {
197     DWORD size;
198     METARECORD *mr;
199     LOGBRUSH logbrush;
200     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
201     BOOL r;
202
203     if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;
204
205     switch(logbrush.lbStyle)
206     {
207     case BS_SOLID:
208     case BS_NULL:
209     case BS_HATCHED:
210         {
211             LOGBRUSH16 lb16;
212
213             lb16.lbStyle = logbrush.lbStyle;
214             lb16.lbColor = logbrush.lbColor;
215             lb16.lbHatch = logbrush.lbHatch;
216             size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
217             mr = HeapAlloc( GetProcessHeap(), 0, size );
218             mr->rdSize = size / 2;
219             mr->rdFunction = META_CREATEBRUSHINDIRECT;
220             memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
221             break;
222         }
223     case BS_PATTERN:
224         {
225             BITMAP bm;
226             BITMAPINFO *info;
227             DWORD bmSize;
228             COLORREF cref;
229
230             GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm);
231             if(bm.bmBitsPixel != 1 || bm.bmPlanes != 1) {
232                 FIXME("Trying to store a colour pattern brush\n");
233                 goto done;
234             }
235
236             bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS);
237
238             size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) +
239               sizeof(RGBQUAD) + bmSize;
240
241             mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
242             if(!mr) goto done;
243             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
244             mr->rdSize = size / 2;
245             mr->rdParm[0] = BS_PATTERN;
246             mr->rdParm[1] = DIB_RGB_COLORS;
247             info = (BITMAPINFO *)(mr->rdParm + 2);
248
249             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
250             info->bmiHeader.biWidth = bm.bmWidth;
251             info->bmiHeader.biHeight = bm.bmHeight;
252             info->bmiHeader.biPlanes = 1;
253             info->bmiHeader.biBitCount = 1;
254             info->bmiHeader.biSizeImage = bmSize;
255
256             GetBitmapBits((HANDLE)logbrush.lbHatch,
257                       bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel),
258                       (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD));
259
260             /* Change the padding to be DIB compatible if needed */
261             if(bm.bmWidth & 31)
262                 MFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
263                       bm.bmWidth, bm.bmHeight);
264             /* BMP and DIB have opposite row order conventions */
265             MFDRV_Reverse((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
266                       bm.bmWidth, bm.bmHeight);
267
268             cref = GetTextColor(physDev->hdc);
269             info->bmiColors[0].rgbRed = GetRValue(cref);
270             info->bmiColors[0].rgbGreen = GetGValue(cref);
271             info->bmiColors[0].rgbBlue = GetBValue(cref);
272             info->bmiColors[0].rgbReserved = 0;
273             cref = GetBkColor(physDev->hdc);
274             info->bmiColors[1].rgbRed = GetRValue(cref);
275             info->bmiColors[1].rgbGreen = GetGValue(cref);
276             info->bmiColors[1].rgbBlue = GetBValue(cref);
277             info->bmiColors[1].rgbReserved = 0;
278             break;
279         }
280
281     case BS_DIBPATTERN:
282         {
283               BITMAPINFO *info;
284               DWORD bmSize, biSize;
285
286               info = GlobalLock16((HGLOBAL16)logbrush.lbHatch);
287               if (info->bmiHeader.biCompression)
288                   bmSize = info->bmiHeader.biSizeImage;
289               else
290                   bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
291                                                 info->bmiHeader.biHeight,
292                                                 info->bmiHeader.biBitCount);
293               biSize = DIB_BitmapInfoSize(info, LOWORD(logbrush.lbColor));
294               size = sizeof(METARECORD) + biSize + bmSize + 2;
295               mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
296               if(!mr) goto done;
297               mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
298               mr->rdSize = size / 2;
299               *(mr->rdParm) = logbrush.lbStyle;
300               *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
301               memcpy(mr->rdParm + 2, info, biSize + bmSize);
302               break;
303         }
304         default:
305             FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
306             return 0;
307     }
308     r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
309     HeapFree(GetProcessHeap(), 0, mr);
310     if( !r )
311         return -1;
312 done:
313     return MFDRV_AddHandle( dev, hBrush );
314 }
315
316
317 /***********************************************************************
318  *           MFDRV_SelectBrush
319  */
320 HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
321 {
322     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
323     INT16 index;
324
325     index = MFDRV_FindObject(dev, hbrush);
326     if( index < 0 )
327     {
328         index = MFDRV_CreateBrushIndirect( dev, hbrush );
329         if( index < 0 )
330             return 0;
331         GDI_hdc_using_object(hbrush, physDev->hdc);
332     }
333     return MFDRV_SelectObject( dev, index ) ? hbrush : HGDI_ERROR;
334 }
335
336 /******************************************************************
337  *         MFDRV_CreateFontIndirect
338  */
339
340 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONT16 *logfont)
341 {
342     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
343     METARECORD *mr = (METARECORD *)&buffer;
344
345     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
346     mr->rdFunction = META_CREATEFONTINDIRECT;
347     memcpy(&(mr->rdParm), logfont, sizeof(LOGFONT16));
348     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
349         return 0;
350     return MFDRV_AddHandle( dev, hFont );
351 }
352
353
354 /***********************************************************************
355  *           MFDRV_SelectFont
356  */
357 HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
358 {
359     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
360     LOGFONT16 lf16;
361     INT16 index;
362
363     index = MFDRV_FindObject(dev, hfont);
364     if( index < 0 )
365     {
366         if (!GetObject16( HFONT_16(hfont), sizeof(lf16), &lf16 ))
367             return HGDI_ERROR;
368         index = MFDRV_CreateFontIndirect(dev, hfont, &lf16);
369         if( index < 0 )
370             return HGDI_ERROR;
371         GDI_hdc_using_object(hfont, physDev->hdc);
372     }
373     return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
374 }
375
376 /******************************************************************
377  *         MFDRV_CreatePenIndirect
378  */
379 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
380 {
381     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
382     METARECORD *mr = (METARECORD *)&buffer;
383
384     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
385     mr->rdFunction = META_CREATEPENINDIRECT;
386     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
387     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
388         return 0;
389     return MFDRV_AddHandle( dev, hPen );
390 }
391
392
393 /***********************************************************************
394  *           MFDRV_SelectPen
395  */
396 HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
397 {
398     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
399     LOGPEN16 logpen;
400     INT16 index;
401
402     index = MFDRV_FindObject(dev, hpen);
403     if( index < 0 )
404     {
405         if (!GetObject16( HPEN_16(hpen), sizeof(logpen), &logpen ))
406         {
407             /* must be an extended pen */
408             EXTLOGPEN *elp;
409             INT size = GetObjectW( hpen, 0, NULL );
410
411             if (!size) return 0;
412
413             elp = HeapAlloc( GetProcessHeap(), 0, size );
414
415             GetObjectW( hpen, size, elp );
416             /* FIXME: add support for user style pens */
417             logpen.lopnStyle = elp->elpPenStyle;
418             logpen.lopnWidth.x = elp->elpWidth;
419             logpen.lopnWidth.y = 0;
420             logpen.lopnColor = elp->elpColor;
421
422             HeapFree( GetProcessHeap(), 0, elp );
423         }
424
425         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
426         if( index < 0 )
427             return 0;
428         GDI_hdc_using_object(hpen, physDev->hdc);
429     }
430     return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
431 }
432
433
434 /******************************************************************
435  *         MFDRV_CreatePalette
436  */
437 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
438 {
439     int index;
440     BOOL ret;
441     METARECORD *mr;
442
443     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
444     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
445     mr->rdFunction = META_CREATEPALETTE;
446     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
447     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
448     {
449         HeapFree(GetProcessHeap(), 0, mr);
450         return FALSE;
451     }
452
453     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
454     mr->rdFunction = META_SELECTPALETTE;
455
456     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
457     else
458     {
459         *(mr->rdParm) = index;
460         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
461     }
462     HeapFree(GetProcessHeap(), 0, mr);
463     return ret;
464 }
465
466
467 /***********************************************************************
468  *           MFDRV_SelectPalette
469  */
470 HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
471 {
472 #define PALVERSION 0x0300
473
474     PLOGPALETTE logPalette;
475     WORD        wNumEntries = 0;
476     BOOL        creationSucceed;
477     int         sizeofPalette;
478
479     GetObjectA(hPalette, sizeof(WORD), (LPSTR) &wNumEntries);
480
481     if (wNumEntries == 0) return 0;
482
483     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
484     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
485
486     if (logPalette == NULL) return 0;
487
488     logPalette->palVersion = PALVERSION;
489     logPalette->palNumEntries = wNumEntries;
490
491     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
492
493     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
494
495     HeapFree( GetProcessHeap(), 0, logPalette );
496
497     if (creationSucceed)
498         return hPalette;
499
500     return 0;
501 }
502
503 /***********************************************************************
504  *           MFDRV_RealizePalette
505  */
506 UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
507 {
508     char buffer[sizeof(METARECORD) - sizeof(WORD)];
509     METARECORD *mr = (METARECORD *)&buffer;
510
511     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
512     mr->rdFunction = META_REALIZEPALETTE;
513
514     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
515
516     /* The return value is suppose to be the number of entries
517        in the logical palette mapped to the system palette or 0
518        if the function failed. Since it's not trivial here to
519        get that kind of information and since it's of little
520        use in the case of metafiles, we'll always return 1. */
521     return 1;
522 }