push 87b6981010d7405c33b14cddcceec21b47729eba
[wine/hacks.git] / dlls / gdi32 / mfdrv / objects.c
blobc6a68cac6fe5ce1fb2137c3c0e6f515e66511e68
1 /*
2 * GDI objects
4 * Copyright 1993 Alexandre Julliard
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.
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.
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
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
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"
35 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
37 /******************************************************************
38 * MFDRV_AddHandle
40 UINT MFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
42 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
43 UINT16 index;
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]));
53 physDev->handles[index] = obj;
55 physDev->cur_handles++;
56 if(physDev->cur_handles > physDev->mh->mtNoObjects)
57 physDev->mh->mtNoObjects++;
59 return index ; /* index 0 is not reserved for metafiles */
62 /******************************************************************
63 * MFDRV_RemoveHandle
65 BOOL MFDRV_RemoveHandle( PHYSDEV dev, UINT index )
67 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
68 BOOL ret = FALSE;
70 if (index < physDev->handles_size && physDev->handles[index])
72 physDev->handles[index] = 0;
73 physDev->cur_handles--;
74 ret = TRUE;
76 return ret;
79 /******************************************************************
80 * MFDRV_FindObject
82 static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
84 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
85 INT16 index;
87 for(index = 0; index < physDev->handles_size; index++)
88 if(physDev->handles[index] == obj) break;
90 if(index == physDev->handles_size) return -1;
92 return index ;
96 /******************************************************************
97 * MFDRV_DeleteObject
99 BOOL CDECL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
101 METARECORD mr;
102 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
103 INT16 index;
104 BOOL ret = TRUE;
106 index = MFDRV_FindObject(dev, obj);
107 if( index < 0 )
108 return 0;
110 mr.rdSize = sizeof mr / 2;
111 mr.rdFunction = META_DELETEOBJECT;
112 mr.rdParm[0] = index;
114 if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
115 ret = FALSE;
117 physDev->handles[index] = 0;
118 physDev->cur_handles--;
119 return ret;
123 /***********************************************************************
124 * MFDRV_SelectObject
126 static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
128 METARECORD mr;
130 mr.rdSize = sizeof mr / 2;
131 mr.rdFunction = META_SELECTOBJECT;
132 mr.rdParm[0] = index;
134 return MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 );
138 /***********************************************************************
139 * MFDRV_SelectBitmap
141 HBITMAP CDECL MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
143 return 0;
146 /***********************************************************************
147 * Internal helper for MFDRV_CreateBrushIndirect():
148 * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
150 static inline void MFDRV_PadTo32(LPBYTE lpRows, int height, int width)
152 int bytes16 = 2 * ((width + 15) / 16);
153 int bytes32 = 4 * ((width + 31) / 32);
154 LPBYTE lpSrc, lpDst;
155 int i;
157 if (!height)
158 return;
160 height = abs(height) - 1;
161 lpSrc = lpRows + height * bytes16;
162 lpDst = lpRows + height * bytes32;
164 /* Note that we work backwards so we can re-pad in place */
165 while (height >= 0)
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--;
177 /***********************************************************************
178 * Internal helper for MFDRV_CreateBrushIndirect():
179 * Reverse order of bitmap rows in going from BMP to DIB.
181 static inline void MFDRV_Reverse(LPBYTE lpRows, int height, int width)
183 int bytes = 4 * ((width + 31) / 32);
184 LPBYTE lpSrc, lpDst;
185 BYTE temp;
186 int i;
188 if (!height)
189 return;
191 lpSrc = lpRows;
192 lpDst = lpRows + (height-1) * bytes;
193 height = height/2;
195 while (height > 0)
197 for (i = 0; i < bytes; i++)
199 temp = lpDst[i];
200 lpDst[i] = lpSrc[i];
201 lpSrc[i] = temp;
203 lpSrc += bytes;
204 lpDst -= bytes;
205 height--;
209 /******************************************************************
210 * MFDRV_CreateBrushIndirect
213 INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
215 DWORD size;
216 METARECORD *mr;
217 LOGBRUSH logbrush;
218 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
219 BOOL r;
221 if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;
223 switch(logbrush.lbStyle)
225 case BS_SOLID:
226 case BS_NULL:
227 case BS_HATCHED:
229 LOGBRUSH16 lb16;
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;
241 case BS_PATTERN:
243 BITMAP bm;
244 BITMAPINFO *info;
245 DWORD bmSize;
246 COLORREF cref;
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;
254 bmSize = DIB_GetDIBImageBytes(bm.bmWidth, bm.bmHeight, DIB_PAL_COLORS);
256 size = sizeof(METARECORD) + sizeof(WORD) + sizeof(BITMAPINFO) +
257 sizeof(RGBQUAD) + bmSize;
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);
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;
274 GetBitmapBits((HANDLE)logbrush.lbHatch,
275 bm.bmHeight * BITMAP_GetWidthBytes (bm.bmWidth, bm.bmBitsPixel),
276 (LPBYTE)info + sizeof(BITMAPINFO) + sizeof(RGBQUAD));
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);
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;
299 case BS_DIBPATTERN:
301 BITMAPINFO *info;
302 DWORD bmSize, biSize;
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)
316 GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
317 goto done;
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;
327 default:
328 FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
329 return 0;
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 );
340 /***********************************************************************
341 * MFDRV_SelectBrush
343 HBRUSH CDECL MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
345 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
346 INT16 index;
348 index = MFDRV_FindObject(dev, hbrush);
349 if( index < 0 )
351 index = MFDRV_CreateBrushIndirect( dev, hbrush );
352 if( index < 0 )
353 return 0;
354 GDI_hdc_using_object(hbrush, physDev->hdc);
356 return MFDRV_SelectObject( dev, index ) ? hbrush : HGDI_ERROR;
359 /******************************************************************
360 * MFDRV_CreateFontIndirect
363 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfont)
365 char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
366 METARECORD *mr = (METARECORD *)&buffer;
367 LOGFONT16 *font16;
368 INT written;
370 mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
371 mr->rdFunction = META_CREATEFONTINDIRECT;
372 font16 = (LOGFONT16 *)&mr->rdParm;
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);
391 if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
392 return 0;
393 return MFDRV_AddHandle( dev, hFont );
397 /***********************************************************************
398 * MFDRV_SelectFont
400 HFONT CDECL MFDRV_SelectFont( PHYSDEV dev, HFONT hfont, HANDLE gdiFont )
402 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
403 LOGFONTW font;
404 INT16 index;
406 index = MFDRV_FindObject(dev, hfont);
407 if( index < 0 )
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);
416 return MFDRV_SelectObject( dev, index ) ? hfont : HGDI_ERROR;
419 /******************************************************************
420 * MFDRV_CreatePenIndirect
422 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
424 char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
425 METARECORD *mr = (METARECORD *)&buffer;
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 );
436 /***********************************************************************
437 * MFDRV_SelectPen
439 HPEN CDECL MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
441 METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
442 LOGPEN16 logpen;
443 INT16 index;
445 index = MFDRV_FindObject(dev, hpen);
446 if( index < 0 )
448 /* must be an extended pen */
449 INT size = GetObjectW( hpen, 0, NULL );
451 if (!size) return 0;
453 if (size == sizeof(LOGPEN))
455 LOGPEN pen;
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;
463 else /* must be an extended pen */
465 EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
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;
474 HeapFree( GetProcessHeap(), 0, elp );
477 index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
478 if( index < 0 )
479 return 0;
480 GDI_hdc_using_object(hpen, physDev->hdc);
482 return MFDRV_SelectObject( dev, index ) ? hpen : HGDI_ERROR;
486 /******************************************************************
487 * MFDRV_CreatePalette
489 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
491 int index;
492 BOOL ret;
493 METARECORD *mr;
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))))
501 HeapFree(GetProcessHeap(), 0, mr);
502 return FALSE;
505 mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
506 mr->rdFunction = META_SELECTPALETTE;
508 if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
509 else
511 *(mr->rdParm) = index;
512 ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
514 HeapFree(GetProcessHeap(), 0, mr);
515 return ret;
519 /***********************************************************************
520 * MFDRV_SelectPalette
522 HPALETTE CDECL MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
524 #define PALVERSION 0x0300
526 PLOGPALETTE logPalette;
527 WORD wNumEntries = 0;
528 BOOL creationSucceed;
529 int sizeofPalette;
531 GetObjectA(hPalette, sizeof(WORD), &wNumEntries);
533 if (wNumEntries == 0) return 0;
535 sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
536 logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
538 if (logPalette == NULL) return 0;
540 logPalette->palVersion = PALVERSION;
541 logPalette->palNumEntries = wNumEntries;
543 GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
545 creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
547 HeapFree( GetProcessHeap(), 0, logPalette );
549 if (creationSucceed)
550 return hPalette;
552 return 0;
555 /***********************************************************************
556 * MFDRV_RealizePalette
558 UINT CDECL MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
560 char buffer[sizeof(METARECORD) - sizeof(WORD)];
561 METARECORD *mr = (METARECORD *)&buffer;
563 mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
564 mr->rdFunction = META_REALIZEPALETTE;
566 if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
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;