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
30 #include "mfdrv/metafiledrv.h"
31 #include "gdi_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(metafile
);
36 /******************************************************************
39 UINT
MFDRV_AddHandle( PHYSDEV dev
, HGDIOBJ obj
)
41 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
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
,
50 physDev
->handles_size
* sizeof(physDev
->handles
[0]));
52 physDev
->handles
[index
] = obj
;
54 physDev
->cur_handles
++;
55 if(physDev
->cur_handles
> physDev
->mh
->mtNoObjects
)
56 physDev
->mh
->mtNoObjects
++;
58 return index
; /* index 0 is not reserved for metafiles */
61 /******************************************************************
64 BOOL
MFDRV_RemoveHandle( PHYSDEV dev
, UINT index
)
66 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
69 if (index
< physDev
->handles_size
&& physDev
->handles
[index
])
71 physDev
->handles
[index
] = 0;
72 physDev
->cur_handles
--;
78 /******************************************************************
81 static INT16
MFDRV_FindObject( PHYSDEV dev
, HGDIOBJ obj
)
83 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
86 for(index
= 0; index
< physDev
->handles_size
; index
++)
87 if(physDev
->handles
[index
] == obj
) break;
89 if(index
== physDev
->handles_size
) return -1;
95 /******************************************************************
98 BOOL CDECL
MFDRV_DeleteObject( PHYSDEV dev
, HGDIOBJ obj
)
101 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
105 index
= MFDRV_FindObject(dev
, obj
);
109 mr
.rdSize
= sizeof mr
/ 2;
110 mr
.rdFunction
= META_DELETEOBJECT
;
111 mr
.rdParm
[0] = index
;
113 if(!MFDRV_WriteRecord( dev
, &mr
, mr
.rdSize
*2 ))
116 physDev
->handles
[index
] = 0;
117 physDev
->cur_handles
--;
122 /***********************************************************************
125 static BOOL
MFDRV_SelectObject( PHYSDEV dev
, INT16 index
)
129 mr
.rdSize
= sizeof mr
/ 2;
130 mr
.rdFunction
= META_SELECTOBJECT
;
131 mr
.rdParm
[0] = index
;
133 return MFDRV_WriteRecord( dev
, &mr
, mr
.rdSize
*2 );
137 /***********************************************************************
140 HBITMAP CDECL
MFDRV_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
145 /***********************************************************************
146 * Internal helper for MFDRV_CreateBrushIndirect():
147 * Change the padding of a bitmap from 16 (BMP) to 32 (DIB) bits.
149 static inline void MFDRV_PadTo32(LPBYTE lpRows
, int height
, int width
)
151 int bytes16
= 2 * ((width
+ 15) / 16);
152 int bytes32
= 4 * ((width
+ 31) / 32);
159 height
= abs(height
) - 1;
160 lpSrc
= lpRows
+ height
* bytes16
;
161 lpDst
= lpRows
+ height
* bytes32
;
163 /* Note that we work backwards so we can re-pad in place */
166 for (i
= bytes32
; i
> bytes16
; i
--)
167 lpDst
[i
- 1] = 0; /* Zero the padding bytes */
169 lpDst
[i
- 1] = lpSrc
[i
- 1]; /* Move image bytes into alignment */
176 /***********************************************************************
177 * Internal helper for MFDRV_CreateBrushIndirect():
178 * Reverse order of bitmap rows in going from BMP to DIB.
180 static inline void MFDRV_Reverse(LPBYTE lpRows
, int height
, int width
)
182 int bytes
= 4 * ((width
+ 31) / 32);
191 lpDst
= lpRows
+ (height
-1) * bytes
;
196 for (i
= 0; i
< bytes
; i
++)
208 /******************************************************************
209 * MFDRV_CreateBrushIndirect
212 INT16
MFDRV_CreateBrushIndirect(PHYSDEV dev
, HBRUSH hBrush
)
217 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
220 if (!GetObjectA( hBrush
, sizeof(logbrush
), &logbrush
)) return -1;
222 switch(logbrush
.lbStyle
)
230 lb16
.lbStyle
= logbrush
.lbStyle
;
231 lb16
.lbColor
= logbrush
.lbColor
;
232 lb16
.lbHatch
= logbrush
.lbHatch
;
233 size
= sizeof(METARECORD
) + sizeof(LOGBRUSH16
) - 2;
234 mr
= HeapAlloc( GetProcessHeap(), 0, size
);
235 mr
->rdSize
= size
/ 2;
236 mr
->rdFunction
= META_CREATEBRUSHINDIRECT
;
237 memcpy( mr
->rdParm
, &lb16
, sizeof(LOGBRUSH16
));
247 GetObjectA((HANDLE
)logbrush
.lbHatch
, sizeof(bm
), &bm
);
248 if(bm
.bmBitsPixel
!= 1 || bm
.bmPlanes
!= 1) {
249 FIXME("Trying to store a colour pattern brush\n");
253 bmSize
= DIB_GetDIBImageBytes(bm
.bmWidth
, bm
.bmHeight
, DIB_PAL_COLORS
);
255 size
= sizeof(METARECORD
) + sizeof(WORD
) + sizeof(BITMAPINFO
) +
256 sizeof(RGBQUAD
) + bmSize
;
258 mr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
260 mr
->rdFunction
= META_DIBCREATEPATTERNBRUSH
;
261 mr
->rdSize
= size
/ 2;
262 mr
->rdParm
[0] = BS_PATTERN
;
263 mr
->rdParm
[1] = DIB_RGB_COLORS
;
264 info
= (BITMAPINFO
*)(mr
->rdParm
+ 2);
266 info
->bmiHeader
.biSize
= sizeof(BITMAPINFOHEADER
);
267 info
->bmiHeader
.biWidth
= bm
.bmWidth
;
268 info
->bmiHeader
.biHeight
= bm
.bmHeight
;
269 info
->bmiHeader
.biPlanes
= 1;
270 info
->bmiHeader
.biBitCount
= 1;
271 info
->bmiHeader
.biSizeImage
= bmSize
;
273 GetBitmapBits((HANDLE
)logbrush
.lbHatch
,
274 bm
.bmHeight
* BITMAP_GetWidthBytes (bm
.bmWidth
, bm
.bmBitsPixel
),
275 (LPBYTE
)info
+ sizeof(BITMAPINFO
) + sizeof(RGBQUAD
));
277 /* Change the padding to be DIB compatible if needed */
279 MFDRV_PadTo32((LPBYTE
)info
+ sizeof(BITMAPINFO
) + sizeof(RGBQUAD
),
280 bm
.bmWidth
, bm
.bmHeight
);
281 /* BMP and DIB have opposite row order conventions */
282 MFDRV_Reverse((LPBYTE
)info
+ sizeof(BITMAPINFO
) + sizeof(RGBQUAD
),
283 bm
.bmWidth
, bm
.bmHeight
);
285 cref
= GetTextColor(physDev
->hdc
);
286 info
->bmiColors
[0].rgbRed
= GetRValue(cref
);
287 info
->bmiColors
[0].rgbGreen
= GetGValue(cref
);
288 info
->bmiColors
[0].rgbBlue
= GetBValue(cref
);
289 info
->bmiColors
[0].rgbReserved
= 0;
290 cref
= GetBkColor(physDev
->hdc
);
291 info
->bmiColors
[1].rgbRed
= GetRValue(cref
);
292 info
->bmiColors
[1].rgbGreen
= GetGValue(cref
);
293 info
->bmiColors
[1].rgbBlue
= GetBValue(cref
);
294 info
->bmiColors
[1].rgbReserved
= 0;
301 DWORD bmSize
, biSize
;
303 info
= GlobalLock( (HGLOBAL
)logbrush
.lbHatch
);
304 if (info
->bmiHeader
.biCompression
)
305 bmSize
= info
->bmiHeader
.biSizeImage
;
307 bmSize
= DIB_GetDIBImageBytes(info
->bmiHeader
.biWidth
,
308 info
->bmiHeader
.biHeight
,
309 info
->bmiHeader
.biBitCount
);
310 biSize
= bitmap_info_size(info
, LOWORD(logbrush
.lbColor
));
311 size
= sizeof(METARECORD
) + biSize
+ bmSize
+ 2;
312 mr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
315 GlobalUnlock( (HGLOBAL
)logbrush
.lbHatch
);
318 mr
->rdFunction
= META_DIBCREATEPATTERNBRUSH
;
319 mr
->rdSize
= size
/ 2;
320 *(mr
->rdParm
) = logbrush
.lbStyle
;
321 *(mr
->rdParm
+ 1) = LOWORD(logbrush
.lbColor
);
322 memcpy(mr
->rdParm
+ 2, info
, biSize
+ bmSize
);
323 GlobalUnlock( (HGLOBAL
)logbrush
.lbHatch
);
327 FIXME("Unkonwn brush style %x\n", logbrush
.lbStyle
);
330 r
= MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* 2);
331 HeapFree(GetProcessHeap(), 0, mr
);
335 return MFDRV_AddHandle( dev
, hBrush
);
339 /***********************************************************************
342 HBRUSH CDECL
MFDRV_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
)
344 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
347 index
= MFDRV_FindObject(dev
, hbrush
);
350 index
= MFDRV_CreateBrushIndirect( dev
, hbrush
);
353 GDI_hdc_using_object(hbrush
, physDev
->hdc
);
355 return MFDRV_SelectObject( dev
, index
) ? hbrush
: HGDI_ERROR
;
358 /******************************************************************
359 * MFDRV_CreateFontIndirect
362 static UINT16
MFDRV_CreateFontIndirect(PHYSDEV dev
, HFONT hFont
, LOGFONTW
*logfont
)
364 char buffer
[sizeof(METARECORD
) - 2 + sizeof(LOGFONT16
)];
365 METARECORD
*mr
= (METARECORD
*)&buffer
;
368 mr
->rdSize
= (sizeof(METARECORD
) + sizeof(LOGFONT16
) - 2) / 2;
369 mr
->rdFunction
= META_CREATEFONTINDIRECT
;
370 font16
= (LOGFONT16
*)&mr
->rdParm
;
372 font16
->lfHeight
= logfont
->lfHeight
;
373 font16
->lfWidth
= logfont
->lfWidth
;
374 font16
->lfEscapement
= logfont
->lfEscapement
;
375 font16
->lfOrientation
= logfont
->lfOrientation
;
376 font16
->lfWeight
= logfont
->lfWeight
;
377 font16
->lfItalic
= logfont
->lfItalic
;
378 font16
->lfUnderline
= logfont
->lfUnderline
;
379 font16
->lfStrikeOut
= logfont
->lfStrikeOut
;
380 font16
->lfCharSet
= logfont
->lfCharSet
;
381 font16
->lfOutPrecision
= logfont
->lfOutPrecision
;
382 font16
->lfClipPrecision
= logfont
->lfClipPrecision
;
383 font16
->lfQuality
= logfont
->lfQuality
;
384 font16
->lfPitchAndFamily
= logfont
->lfPitchAndFamily
;
385 WideCharToMultiByte( CP_ACP
, 0, logfont
->lfFaceName
, -1, font16
->lfFaceName
, LF_FACESIZE
, NULL
, NULL
);
386 font16
->lfFaceName
[LF_FACESIZE
-1] = 0;
388 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* 2)))
390 return MFDRV_AddHandle( dev
, hFont
);
394 /***********************************************************************
397 HFONT CDECL
MFDRV_SelectFont( PHYSDEV dev
, HFONT hfont
, HANDLE gdiFont
)
399 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
403 index
= MFDRV_FindObject(dev
, hfont
);
406 if (!GetObjectW( hfont
, sizeof(font
), &font
))
408 index
= MFDRV_CreateFontIndirect(dev
, hfont
, &font
);
411 GDI_hdc_using_object(hfont
, physDev
->hdc
);
413 return MFDRV_SelectObject( dev
, index
) ? hfont
: HGDI_ERROR
;
416 /******************************************************************
417 * MFDRV_CreatePenIndirect
419 static UINT16
MFDRV_CreatePenIndirect(PHYSDEV dev
, HPEN hPen
, LOGPEN16
*logpen
)
421 char buffer
[sizeof(METARECORD
) - 2 + sizeof(*logpen
)];
422 METARECORD
*mr
= (METARECORD
*)&buffer
;
424 mr
->rdSize
= (sizeof(METARECORD
) + sizeof(*logpen
) - 2) / 2;
425 mr
->rdFunction
= META_CREATEPENINDIRECT
;
426 memcpy(&(mr
->rdParm
), logpen
, sizeof(*logpen
));
427 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* 2)))
429 return MFDRV_AddHandle( dev
, hPen
);
433 /***********************************************************************
436 HPEN CDECL
MFDRV_SelectPen( PHYSDEV dev
, HPEN hpen
)
438 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
442 index
= MFDRV_FindObject(dev
, hpen
);
445 /* must be an extended pen */
446 INT size
= GetObjectW( hpen
, 0, NULL
);
450 if (size
== sizeof(LOGPEN
))
454 GetObjectW( hpen
, sizeof(pen
), &pen
);
455 logpen
.lopnStyle
= pen
.lopnStyle
;
456 logpen
.lopnWidth
.x
= pen
.lopnWidth
.x
;
457 logpen
.lopnWidth
.y
= pen
.lopnWidth
.y
;
458 logpen
.lopnColor
= pen
.lopnColor
;
460 else /* must be an extended pen */
462 EXTLOGPEN
*elp
= HeapAlloc( GetProcessHeap(), 0, size
);
464 GetObjectW( hpen
, size
, elp
);
465 /* FIXME: add support for user style pens */
466 logpen
.lopnStyle
= elp
->elpPenStyle
;
467 logpen
.lopnWidth
.x
= elp
->elpWidth
;
468 logpen
.lopnWidth
.y
= 0;
469 logpen
.lopnColor
= elp
->elpColor
;
471 HeapFree( GetProcessHeap(), 0, elp
);
474 index
= MFDRV_CreatePenIndirect( dev
, hpen
, &logpen
);
477 GDI_hdc_using_object(hpen
, physDev
->hdc
);
479 return MFDRV_SelectObject( dev
, index
) ? hpen
: HGDI_ERROR
;
483 /******************************************************************
484 * MFDRV_CreatePalette
486 static BOOL
MFDRV_CreatePalette(PHYSDEV dev
, HPALETTE hPalette
, LOGPALETTE
* logPalette
, int sizeofPalette
)
492 mr
= HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD
) + sizeofPalette
- sizeof(WORD
) );
493 mr
->rdSize
= (sizeof(METARECORD
) + sizeofPalette
- sizeof(WORD
)) / sizeof(WORD
);
494 mr
->rdFunction
= META_CREATEPALETTE
;
495 memcpy(&(mr
->rdParm
), logPalette
, sizeofPalette
);
496 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* sizeof(WORD
))))
498 HeapFree(GetProcessHeap(), 0, mr
);
502 mr
->rdSize
= sizeof(METARECORD
) / sizeof(WORD
);
503 mr
->rdFunction
= META_SELECTPALETTE
;
505 if ((index
= MFDRV_AddHandle( dev
, hPalette
)) == -1) ret
= FALSE
;
508 *(mr
->rdParm
) = index
;
509 ret
= MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* sizeof(WORD
));
511 HeapFree(GetProcessHeap(), 0, mr
);
516 /***********************************************************************
517 * MFDRV_SelectPalette
519 HPALETTE CDECL
MFDRV_SelectPalette( PHYSDEV dev
, HPALETTE hPalette
, BOOL bForceBackground
)
521 #define PALVERSION 0x0300
523 PLOGPALETTE logPalette
;
524 WORD wNumEntries
= 0;
525 BOOL creationSucceed
;
528 GetObjectA(hPalette
, sizeof(WORD
), &wNumEntries
);
530 if (wNumEntries
== 0) return 0;
532 sizeofPalette
= sizeof(LOGPALETTE
) + ((wNumEntries
-1) * sizeof(PALETTEENTRY
));
533 logPalette
= HeapAlloc( GetProcessHeap(), 0, sizeofPalette
);
535 if (logPalette
== NULL
) return 0;
537 logPalette
->palVersion
= PALVERSION
;
538 logPalette
->palNumEntries
= wNumEntries
;
540 GetPaletteEntries(hPalette
, 0, wNumEntries
, logPalette
->palPalEntry
);
542 creationSucceed
= MFDRV_CreatePalette( dev
, hPalette
, logPalette
, sizeofPalette
);
544 HeapFree( GetProcessHeap(), 0, logPalette
);
552 /***********************************************************************
553 * MFDRV_RealizePalette
555 UINT CDECL
MFDRV_RealizePalette(PHYSDEV dev
, HPALETTE hPalette
, BOOL dummy
)
557 char buffer
[sizeof(METARECORD
) - sizeof(WORD
)];
558 METARECORD
*mr
= (METARECORD
*)&buffer
;
560 mr
->rdSize
= (sizeof(METARECORD
) - sizeof(WORD
)) / sizeof(WORD
);
561 mr
->rdFunction
= META_REALIZEPALETTE
;
563 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* sizeof(WORD
)))) return 0;
565 /* The return value is suppose to be the number of entries
566 in the logical palette mapped to the system palette or 0
567 if the function failed. Since it's not trivial here to
568 get that kind of information and since it's of little
569 use in the case of metafiles, we'll always return 1. */