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 "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 /******************************************************************
40 UINT
MFDRV_AddHandle( PHYSDEV dev
, HGDIOBJ obj
)
42 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
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
,
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 /******************************************************************
65 BOOL
MFDRV_RemoveHandle( PHYSDEV dev
, UINT index
)
67 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
70 if (index
< physDev
->handles_size
&& physDev
->handles
[index
])
72 physDev
->handles
[index
] = 0;
73 physDev
->cur_handles
--;
79 /******************************************************************
82 static INT16
MFDRV_FindObject( PHYSDEV dev
, HGDIOBJ obj
)
84 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
87 for(index
= 0; index
< physDev
->handles_size
; index
++)
88 if(physDev
->handles
[index
] == obj
) break;
90 if(index
== physDev
->handles_size
) return -1;
96 /******************************************************************
99 BOOL CDECL
MFDRV_DeleteObject( PHYSDEV dev
, HGDIOBJ obj
)
102 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
106 index
= MFDRV_FindObject(dev
, obj
);
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 ))
117 physDev
->handles
[index
] = 0;
118 physDev
->cur_handles
--;
123 /***********************************************************************
126 static BOOL
MFDRV_SelectObject( PHYSDEV dev
, INT16 index
)
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 /***********************************************************************
141 HBITMAP CDECL
MFDRV_SelectBitmap( PHYSDEV dev
, HBITMAP hbitmap
)
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);
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 */
167 for (i
= bytes32
; i
> bytes16
; i
--)
168 lpDst
[i
- 1] = 0; /* Zero the padding bytes */
170 lpDst
[i
- 1] = lpSrc
[i
- 1]; /* Move image bytes into alignment */
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);
192 lpDst
= lpRows
+ (height
-1) * bytes
;
197 for (i
= 0; i
< bytes
; i
++)
209 /******************************************************************
210 * MFDRV_CreateBrushIndirect
213 INT16
MFDRV_CreateBrushIndirect(PHYSDEV dev
, HBRUSH hBrush
)
218 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
221 if (!GetObjectA( hBrush
, sizeof(logbrush
), &logbrush
)) return -1;
223 switch(logbrush
.lbStyle
)
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
));
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");
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
);
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 */
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;
302 DWORD bmSize
, biSize
;
304 info
= GlobalLock( (HGLOBAL
)logbrush
.lbHatch
);
305 if (info
->bmiHeader
.biCompression
)
306 bmSize
= info
->bmiHeader
.biSizeImage
;
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
);
316 GlobalUnlock( (HGLOBAL
)logbrush
.lbHatch
);
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
);
328 FIXME("Unkonwn brush style %x\n", logbrush
.lbStyle
);
331 r
= MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* 2);
332 HeapFree(GetProcessHeap(), 0, mr
);
336 return MFDRV_AddHandle( dev
, hBrush
);
340 /***********************************************************************
343 HBRUSH CDECL
MFDRV_SelectBrush( PHYSDEV dev
, HBRUSH hbrush
)
345 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
348 index
= MFDRV_FindObject(dev
, hbrush
);
351 index
= MFDRV_CreateBrushIndirect( dev
, hbrush
);
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
;
369 mr
->rdSize
= (sizeof(METARECORD
) + sizeof(LOGFONT16
) - 2) / 2;
370 mr
->rdFunction
= META_CREATEFONTINDIRECT
;
371 font16
= (LOGFONT16
*)&mr
->rdParm
;
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;
389 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* 2)))
391 return MFDRV_AddHandle( dev
, hFont
);
395 /***********************************************************************
398 HFONT CDECL
MFDRV_SelectFont( PHYSDEV dev
, HFONT hfont
, HANDLE gdiFont
)
400 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
404 index
= MFDRV_FindObject(dev
, hfont
);
407 if (!GetObjectW( hfont
, sizeof(font
), &font
))
409 index
= MFDRV_CreateFontIndirect(dev
, hfont
, &font
);
412 GDI_hdc_using_object(hfont
, physDev
->hdc
);
414 return MFDRV_SelectObject( dev
, index
) ? hfont
: HGDI_ERROR
;
417 /******************************************************************
418 * MFDRV_CreatePenIndirect
420 static UINT16
MFDRV_CreatePenIndirect(PHYSDEV dev
, HPEN hPen
, LOGPEN16
*logpen
)
422 char buffer
[sizeof(METARECORD
) - 2 + sizeof(*logpen
)];
423 METARECORD
*mr
= (METARECORD
*)&buffer
;
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)))
430 return MFDRV_AddHandle( dev
, hPen
);
434 /***********************************************************************
437 HPEN CDECL
MFDRV_SelectPen( PHYSDEV dev
, HPEN hpen
)
439 METAFILEDRV_PDEVICE
*physDev
= (METAFILEDRV_PDEVICE
*)dev
;
443 index
= MFDRV_FindObject(dev
, hpen
);
446 /* must be an extended pen */
447 INT size
= GetObjectW( hpen
, 0, NULL
);
451 if (size
== sizeof(LOGPEN
))
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
;
461 else /* must be an extended pen */
463 EXTLOGPEN
*elp
= HeapAlloc( GetProcessHeap(), 0, size
);
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
;
472 HeapFree( GetProcessHeap(), 0, elp
);
475 index
= MFDRV_CreatePenIndirect( dev
, hpen
, &logpen
);
478 GDI_hdc_using_object(hpen
, physDev
->hdc
);
480 return MFDRV_SelectObject( dev
, index
) ? hpen
: HGDI_ERROR
;
484 /******************************************************************
485 * MFDRV_CreatePalette
487 static BOOL
MFDRV_CreatePalette(PHYSDEV dev
, HPALETTE hPalette
, LOGPALETTE
* logPalette
, int sizeofPalette
)
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
))))
499 HeapFree(GetProcessHeap(), 0, mr
);
503 mr
->rdSize
= sizeof(METARECORD
) / sizeof(WORD
);
504 mr
->rdFunction
= META_SELECTPALETTE
;
506 if ((index
= MFDRV_AddHandle( dev
, hPalette
)) == -1) ret
= FALSE
;
509 *(mr
->rdParm
) = index
;
510 ret
= MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* sizeof(WORD
));
512 HeapFree(GetProcessHeap(), 0, mr
);
517 /***********************************************************************
518 * MFDRV_SelectPalette
520 HPALETTE CDECL
MFDRV_SelectPalette( PHYSDEV dev
, HPALETTE hPalette
, BOOL bForceBackground
)
522 #define PALVERSION 0x0300
524 PLOGPALETTE logPalette
;
525 WORD wNumEntries
= 0;
526 BOOL creationSucceed
;
529 GetObjectA(hPalette
, sizeof(WORD
), &wNumEntries
);
531 if (wNumEntries
== 0) return 0;
533 sizeofPalette
= sizeof(LOGPALETTE
) + ((wNumEntries
-1) * sizeof(PALETTEENTRY
));
534 logPalette
= HeapAlloc( GetProcessHeap(), 0, sizeofPalette
);
536 if (logPalette
== NULL
) return 0;
538 logPalette
->palVersion
= PALVERSION
;
539 logPalette
->palNumEntries
= wNumEntries
;
541 GetPaletteEntries(hPalette
, 0, wNumEntries
, logPalette
->palPalEntry
);
543 creationSucceed
= MFDRV_CreatePalette( dev
, hPalette
, logPalette
, sizeofPalette
);
545 HeapFree( GetProcessHeap(), 0, logPalette
);
553 /***********************************************************************
554 * MFDRV_RealizePalette
556 UINT CDECL
MFDRV_RealizePalette(PHYSDEV dev
, HPALETTE hPalette
, BOOL dummy
)
558 char buffer
[sizeof(METARECORD
) - sizeof(WORD
)];
559 METARECORD
*mr
= (METARECORD
*)&buffer
;
561 mr
->rdSize
= (sizeof(METARECORD
) - sizeof(WORD
)) / sizeof(WORD
);
562 mr
->rdFunction
= META_REALIZEPALETTE
;
564 if (!(MFDRV_WriteRecord( dev
, mr
, mr
->rdSize
* sizeof(WORD
)))) return 0;
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. */