gdi32: Graphics driver functions no longer need to be CDECL.
[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  * Internal helper for MFDRV_CreateBrushIndirect():
147  * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
148  */
149 static inline void MFDRV_PadTo32(LPBYTE lpRows, int height, int width)
150 {
151     int bytes16 = 2 * ((width + 15) / 16);
152     int bytes32 = 4 * ((width + 31) / 32);
153     LPBYTE lpSrc, lpDst;
154     int i;
155
156     if (!height)
157         return;
158
159     height = abs(height) - 1;
160     lpSrc = lpRows + height * bytes16;
161     lpDst = lpRows + height * bytes32;
162
163     /* Note that we work backwards so we can re-pad in place */
164     while (height >= 0)
165     {
166         for (i = bytes32; i > bytes16; i--)
167             lpDst[i - 1] = 0; /* Zero the padding bytes */
168         for (; i > 0; i--)
169             lpDst[i - 1] = lpSrc[i - 1]; /* Move image bytes into alignment */
170         lpSrc -= bytes16;
171         lpDst -= bytes32;
172         height--;
173     }
174 }
175
176 /***********************************************************************
177  * Internal helper for MFDRV_CreateBrushIndirect():
178  * Reverse order of bitmap rows in going from BMP to DIB.
179  */
180 static inline void MFDRV_Reverse(LPBYTE lpRows, int height, int width)
181 {
182     int bytes = 4 * ((width + 31) / 32);
183     LPBYTE lpSrc, lpDst;
184     BYTE temp;
185     int i;
186
187     if (!height)
188         return;
189
190     lpSrc = lpRows;
191     lpDst = lpRows + (height-1) * bytes;
192     height = height/2;
193
194     while (height > 0)
195     {
196         for (i = 0; i < bytes; i++)
197         {
198             temp = lpDst[i];
199             lpDst[i] = lpSrc[i];
200             lpSrc[i] = temp;
201         }
202         lpSrc += bytes;
203         lpDst -= bytes;
204         height--;
205     }
206 }
207
208 /******************************************************************
209  *         MFDRV_CreateBrushIndirect
210  */
211
212 INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
213 {
214     DWORD size;
215     METARECORD *mr;
216     LOGBRUSH logbrush;
217     BOOL r;
218
219     if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;
220
221     switch(logbrush.lbStyle)
222     {
223     case BS_SOLID:
224     case BS_NULL:
225     case BS_HATCHED:
226         {
227             LOGBRUSH16 lb16;
228
229             lb16.lbStyle = logbrush.lbStyle;
230             lb16.lbColor = logbrush.lbColor;
231             lb16.lbHatch = logbrush.lbHatch;
232             size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
233             mr = HeapAlloc( GetProcessHeap(), 0, size );
234             mr->rdSize = size / 2;
235             mr->rdFunction = META_CREATEBRUSHINDIRECT;
236             memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
237             break;
238         }
239     case BS_PATTERN:
240         {
241             BITMAP bm;
242             BITMAPINFO *info;
243             DWORD bmSize;
244             COLORREF cref;
245
246             GetObjectA((HANDLE)logbrush.lbHatch, sizeof(bm), &bm);
247             if(bm.bmBitsPixel != 1 || bm.bmPlanes != 1) {
248                 FIXME("Trying to store a colour pattern brush\n");
249                 goto done;
250             }
251
252             bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS);
253
254             size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) +
255               sizeof(RGBQUAD) + bmSize;
256
257             mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
258             if(!mr) goto done;
259             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
260             mr->rdSize = size / 2;
261             mr->rdParm[0] = BS_PATTERN;
262             mr->rdParm[1] = DIB_RGB_COLORS;
263             info = (BITMAPINFO *)(mr->rdParm + 2);
264
265             info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
266             info->bmiHeader.biWidth = bm.bmWidth;
267             info->bmiHeader.biHeight = bm.bmHeight;
268             info->bmiHeader.biPlanes = 1;
269             info->bmiHeader.biBitCount = 1;
270             info->bmiHeader.biSizeImage = bmSize;
271
272             GetBitmapBits((HANDLE)logbrush.lbHatch,
273                       bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel),
274                       (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD));
275
276             /* Change the padding to be DIB compatible if needed */
277             if(bm.bmWidth & 31)
278                 MFDRV_PadTo32((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
279                       bm.bmWidth, bm.bmHeight);
280             /* BMP and DIB have opposite row order conventions */
281             MFDRV_Reverse((LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD),
282                       bm.bmWidth, bm.bmHeight);
283
284             cref = GetTextColor( dev->hdc );
285             info->bmiColors[0].rgbRed = GetRValue(cref);
286             info->bmiColors[0].rgbGreen = GetGValue(cref);
287             info->bmiColors[0].rgbBlue = GetBValue(cref);
288             info->bmiColors[0].rgbReserved = 0;
289             cref = GetBkColor( dev->hdc );
290             info->bmiColors[1].rgbRed = GetRValue(cref);
291             info->bmiColors[1].rgbGreen = GetGValue(cref);
292             info->bmiColors[1].rgbBlue = GetBValue(cref);
293             info->bmiColors[1].rgbReserved = 0;
294             break;
295         }
296
297     case BS_DIBPATTERN:
298         {
299               BITMAPINFO *info;
300               DWORD bmSize, biSize;
301
302               info = GlobalLock( (HGLOBAL)logbrush.lbHatch );
303               if (info->bmiHeader.biCompression)
304                   bmSize = info->bmiHeader.biSizeImage;
305               else
306                   bmSize = DIB_GetDIBImageBytes(info->bmiHeader.biWidth,
307                                                 info->bmiHeader.biHeight,
308                                                 info->bmiHeader.biBitCount);
309               biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor));
310               size = sizeof(METARECORD) + biSize + bmSize + 2;
311               mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
312               if (!mr)
313               {
314                   GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
315                   goto done;
316               }
317               mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
318               mr->rdSize = size / 2;
319               *(mr->rdParm) = logbrush.lbStyle;
320               *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
321               memcpy(mr->rdParm + 2, info, biSize + bmSize);
322               GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
323               break;
324         }
325         default:
326             FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
327             return 0;
328     }
329     r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
330     HeapFree(GetProcessHeap(), 0, mr);
331     if( !r )
332         return -1;
333 done:
334     return MFDRV_AddHandle( dev, hBrush );
335 }
336
337
338 /***********************************************************************
339  *           MFDRV_SelectBrush
340  */
341 HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
342 {
343     INT16 index;
344
345     index = MFDRV_FindObject(dev, hbrush);
346     if( index < 0 )
347     {
348         index = MFDRV_CreateBrushIndirect( dev, hbrush );
349         if( index < 0 )
350             return 0;
351         GDI_hdc_using_object(hbrush, dev->hdc);
352     }
353     return MFDRV_SelectObject( dev, index ) ? hbrush : HGDI_ERROR;
354 }
355
356 /******************************************************************
357  *         MFDRV_CreateFontIndirect
358  */
359
360 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfont)
361 {
362     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
363     METARECORD *mr = (METARECORD *)&buffer;
364     LOGFONT16 *font16;
365     INT written;
366
367     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
368     mr->rdFunction = META_CREATEFONTINDIRECT;
369     font16 = (LOGFONT16 *)&mr->rdParm;
370
371     font16->lfHeight         = logfont->lfHeight;
372     font16->lfWidth          = logfont->lfWidth;
373     font16->lfEscapement     = logfont->lfEscapement;
374     font16->lfOrientation    = logfont->lfOrientation;
375     font16->lfWeight         = logfont->lfWeight;
376     font16->lfItalic         = logfont->lfItalic;
377     font16->lfUnderline      = logfont->lfUnderline;
378     font16->lfStrikeOut      = logfont->lfStrikeOut;
379     font16->lfCharSet        = logfont->lfCharSet;
380     font16->lfOutPrecision   = logfont->lfOutPrecision;
381     font16->lfClipPrecision  = logfont->lfClipPrecision;
382     font16->lfQuality        = logfont->lfQuality;
383     font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
384     written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName, LF_FACESIZE - 1, NULL, NULL );
385     /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
386     memset(font16->lfFaceName + written, 0, LF_FACESIZE - written);
387
388     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
389         return 0;
390     return MFDRV_AddHandle( dev, hFont );
391 }
392
393
394 /***********************************************************************
395  *           MFDRV_SelectFont
396  */
397 HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
398 {
399     LOGFONTW font;
400     INT16 index;
401
402     index = MFDRV_FindObject(dev, hfont);
403     if( index < 0 )
404     {
405         if (!GetObjectW( hfont, sizeof(font), &font ))
406             return HGDI_ERROR;
407         index = MFDRV_CreateFontIndirect(dev, hfont, &font);
408         if( index < 0 )
409             return HGDI_ERROR;
410         GDI_hdc_using_object(hfont, dev->hdc);
411     }
412     return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
413 }
414
415 /******************************************************************
416  *         MFDRV_CreatePenIndirect
417  */
418 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
419 {
420     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
421     METARECORD *mr = (METARECORD *)&buffer;
422
423     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
424     mr->rdFunction = META_CREATEPENINDIRECT;
425     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
426     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
427         return 0;
428     return MFDRV_AddHandle( dev, hPen );
429 }
430
431
432 /***********************************************************************
433  *           MFDRV_SelectPen
434  */
435 HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
436 {
437     LOGPEN16 logpen;
438     INT16 index;
439
440     index = MFDRV_FindObject(dev, hpen);
441     if( index < 0 )
442     {
443         /* must be an extended pen */
444         INT size = GetObjectW( hpen, 0, NULL );
445
446         if (!size) return 0;
447
448         if (size == sizeof(LOGPEN))
449         {
450             LOGPEN pen;
451
452             GetObjectW( hpen, sizeof(pen), &pen );
453             logpen.lopnStyle   = pen.lopnStyle;
454             logpen.lopnWidth.x = pen.lopnWidth.x;
455             logpen.lopnWidth.y = pen.lopnWidth.y;
456             logpen.lopnColor   = pen.lopnColor;
457         }
458         else  /* must be an extended pen */
459         {
460             EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
461
462             GetObjectW( hpen, size, elp );
463             /* FIXME: add support for user style pens */
464             logpen.lopnStyle = elp->elpPenStyle;
465             logpen.lopnWidth.x = elp->elpWidth;
466             logpen.lopnWidth.y = 0;
467             logpen.lopnColor = elp->elpColor;
468
469             HeapFree( GetProcessHeap(), 0, elp );
470         }
471
472         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
473         if( index < 0 )
474             return 0;
475         GDI_hdc_using_object(hpen, dev->hdc);
476     }
477     return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
478 }
479
480
481 /******************************************************************
482  *         MFDRV_CreatePalette
483  */
484 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
485 {
486     int index;
487     BOOL ret;
488     METARECORD *mr;
489
490     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
491     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
492     mr->rdFunction = META_CREATEPALETTE;
493     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
494     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
495     {
496         HeapFree(GetProcessHeap(), 0, mr);
497         return FALSE;
498     }
499
500     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
501     mr->rdFunction = META_SELECTPALETTE;
502
503     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
504     else
505     {
506         *(mr->rdParm) = index;
507         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
508     }
509     HeapFree(GetProcessHeap(), 0, mr);
510     return ret;
511 }
512
513
514 /***********************************************************************
515  *           MFDRV_SelectPalette
516  */
517 HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
518 {
519 #define PALVERSION 0x0300
520
521     PLOGPALETTE logPalette;
522     WORD        wNumEntries = 0;
523     BOOL        creationSucceed;
524     int         sizeofPalette;
525
526     GetObjectA(hPalette, sizeof(WORD), &wNumEntries);
527
528     if (wNumEntries == 0) return 0;
529
530     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
531     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
532
533     if (logPalette == NULL) return 0;
534
535     logPalette->palVersion = PALVERSION;
536     logPalette->palNumEntries = wNumEntries;
537
538     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
539
540     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
541
542     HeapFree( GetProcessHeap(), 0, logPalette );
543
544     if (creationSucceed)
545         return hPalette;
546
547     return 0;
548 }
549
550 /***********************************************************************
551  *           MFDRV_RealizePalette
552  */
553 UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
554 {
555     char buffer[sizeof(METARECORD) - sizeof(WORD)];
556     METARECORD *mr = (METARECORD *)&buffer;
557
558     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
559     mr->rdFunction = META_REALIZEPALETTE;
560
561     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
562
563     /* The return value is suppose to be the number of entries
564        in the logical palette mapped to the system palette or 0
565        if the function failed. Since it's not trivial here to
566        get that kind of information and since it's of little
567        use in the case of metafiles, we'll always return 1. */
568     return 1;
569 }