shlwapi: Beginning implementation of IUnknown_QueryServiceForWebBrowserApp.
[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
369     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
370     mr->rdFunction = META_CREATEFONTINDIRECT;
371     font16 = (LOGFONT16 *)&mr->rdParm;
372
373     font16->lfHeight         = logfont->lfHeight;
374     font16->lfWidth          = logfont->lfWidth;
375     font16->lfEscapement     = logfont->lfEscapement;
376     font16->lfOrientation    = logfont->lfOrientation;
377     font16->lfWeight         = logfont->lfWeight;
378     font16->lfItalic         = logfont->lfItalic;
379     font16->lfUnderline      = logfont->lfUnderline;
380     font16->lfStrikeOut      = logfont->lfStrikeOut;
381     font16->lfCharSet        = logfont->lfCharSet;
382     font16->lfOutPrecision   = logfont->lfOutPrecision;
383     font16->lfClipPrecision  = logfont->lfClipPrecision;
384     font16->lfQuality        = logfont->lfQuality;
385     font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
386     WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName, LF_FACESIZE, NULL, NULL );
387     font16->lfFaceName[LF_FACESIZE-1] = 0;
388
389     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
390         return 0;
391     return MFDRV_AddHandle( dev, hFont );
392 }
393
394
395 /***********************************************************************
396  *           MFDRV_SelectFont
397  */
398 HFONT CDECL MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
399 {
400     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
401     LOGFONTW font;
402     INT16 index;
403
404     index = MFDRV_FindObject(dev, hfont);
405     if( index < 0 )
406     {
407         if (!GetObjectW( hfont, sizeof(font), &font ))
408             return HGDI_ERROR;
409         index = MFDRV_CreateFontIndirect(dev, hfont, &font);
410         if( index < 0 )
411             return HGDI_ERROR;
412         GDI_hdc_using_object(hfont, physDev->hdc);
413     }
414     return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
415 }
416
417 /******************************************************************
418  *         MFDRV_CreatePenIndirect
419  */
420 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
421 {
422     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
423     METARECORD *mr = (METARECORD *)&buffer;
424
425     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
426     mr->rdFunction = META_CREATEPENINDIRECT;
427     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
428     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
429         return 0;
430     return MFDRV_AddHandle( dev, hPen );
431 }
432
433
434 /***********************************************************************
435  *           MFDRV_SelectPen
436  */
437 HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
438 {
439     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
440     LOGPEN16 logpen;
441     INT16 index;
442
443     index = MFDRV_FindObject(dev, hpen);
444     if( index < 0 )
445     {
446         /* must be an extended pen */
447         INT size = GetObjectW( hpen, 0, NULL );
448
449         if (!size) return 0;
450
451         if (size == sizeof(LOGPEN))
452         {
453             LOGPEN pen;
454
455             GetObjectW( hpen, sizeof(pen), &pen );
456             logpen.lopnStyle   = pen.lopnStyle;
457             logpen.lopnWidth.x = pen.lopnWidth.x;
458             logpen.lopnWidth.y = pen.lopnWidth.y;
459             logpen.lopnColor   = pen.lopnColor;
460         }
461         else  /* must be an extended pen */
462         {
463             EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
464
465             GetObjectW( hpen, size, elp );
466             /* FIXME: add support for user style pens */
467             logpen.lopnStyle = elp->elpPenStyle;
468             logpen.lopnWidth.x = elp->elpWidth;
469             logpen.lopnWidth.y = 0;
470             logpen.lopnColor = elp->elpColor;
471
472             HeapFree( GetProcessHeap(), 0, elp );
473         }
474
475         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
476         if( index < 0 )
477             return 0;
478         GDI_hdc_using_object(hpen, physDev->hdc);
479     }
480     return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
481 }
482
483
484 /******************************************************************
485  *         MFDRV_CreatePalette
486  */
487 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
488 {
489     int index;
490     BOOL ret;
491     METARECORD *mr;
492
493     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
494     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
495     mr->rdFunction = META_CREATEPALETTE;
496     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
497     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
498     {
499         HeapFree(GetProcessHeap(), 0, mr);
500         return FALSE;
501     }
502
503     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
504     mr->rdFunction = META_SELECTPALETTE;
505
506     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
507     else
508     {
509         *(mr->rdParm) = index;
510         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
511     }
512     HeapFree(GetProcessHeap(), 0, mr);
513     return ret;
514 }
515
516
517 /***********************************************************************
518  *           MFDRV_SelectPalette
519  */
520 HPALETTE CDECL MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
521 {
522 #define PALVERSION 0x0300
523
524     PLOGPALETTE logPalette;
525     WORD        wNumEntries = 0;
526     BOOL        creationSucceed;
527     int         sizeofPalette;
528
529     GetObjectA(hPalette, sizeof(WORD), &wNumEntries);
530
531     if (wNumEntries == 0) return 0;
532
533     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
534     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
535
536     if (logPalette == NULL) return 0;
537
538     logPalette->palVersion = PALVERSION;
539     logPalette->palNumEntries = wNumEntries;
540
541     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
542
543     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
544
545     HeapFree( GetProcessHeap(), 0, logPalette );
546
547     if (creationSucceed)
548         return hPalette;
549
550     return 0;
551 }
552
553 /***********************************************************************
554  *           MFDRV_RealizePalette
555  */
556 UINT CDECL MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
557 {
558     char buffer[sizeof(METARECORD) - sizeof(WORD)];
559     METARECORD *mr = (METARECORD *)&buffer;
560
561     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
562     mr->rdFunction = META_REALIZEPALETTE;
563
564     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
565
566     /* The return value is suppose to be the number of entries
567        in the logical palette mapped to the system palette or 0
568        if the function failed. Since it's not trivial here to
569        get that kind of information and since it's of little
570        use in the case of metafiles, we'll always return 1. */
571     return 1;
572 }