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