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