4 * Copyright David W. Metcalfe, 1994
5 * Copyright Niels de Carpentier, 1996
6 * Copyright Albrecht Kleine, 1996
7 * Copyright Huw Davies, 1996
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 * These functions are primarily involved with metafile playback or anything
26 * that touches a HMETAFILE.
27 * For recording of metafiles look in graphics/metafiledrv/
29 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
30 * global memory handles so these cannot be interchanged.
32 * Memory-based metafiles are just stored as a continuous block of memory with
33 * a METAHEADER at the head with METARECORDs appended to it. mtType is
34 * METAFILE_MEMORY (1). Note this is identical to the disk image of a
35 * disk-based metafile - even mtType is METAFILE_MEMORY.
36 * 16bit HMETAFILE16s are global handles to this block
37 * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
39 * Disk-based metafiles are rather different. HMETAFILE16s point to a
40 * METAHEADER which has mtType equal to METAFILE_DISK (2). Following the 9
41 * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
42 * more 0, then 2 which may be a time stamp of the file and then the path of
43 * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
58 #include "gdi_private.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(metafile
);
65 static CRITICAL_SECTION metafile_cs
;
66 static CRITICAL_SECTION_DEBUG critsect_debug
=
69 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
70 0, 0, { (DWORD_PTR
)(__FILE__
": metafile_cs") }
72 static CRITICAL_SECTION metafile_cs
= { &critsect_debug
, -1, 0, 0, 0, 0 };
74 /******************************************************************
77 * Add a handle to an external handle table and return the index
79 static int MF_AddHandle(HANDLETABLE
*ht
, UINT htlen
, HGDIOBJ hobj
)
83 for (i
= 0; i
< htlen
; i
++)
85 if (*(ht
->objectHandle
+ i
) == 0)
87 *(ht
->objectHandle
+ i
) = hobj
;
95 /******************************************************************
96 * MF_Create_HMETATFILE
98 * Creates a (32 bit) HMETAFILE object from a METAHEADER
100 * HMETAFILEs are GDI objects.
102 HMETAFILE
MF_Create_HMETAFILE(METAHEADER
*mh
)
106 if (!(handle
= NtGdiCreateClientObj( NTGDI_OBJ_METAFILE
)))
109 set_gdi_client_ptr( handle
, mh
);
113 static int bitmap_info_size( const BITMAPINFO
*info
, WORD coloruse
)
115 unsigned int colors
, size
, masks
= 0;
117 if (info
->bmiHeader
.biSize
== sizeof(BITMAPCOREHEADER
))
119 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
120 colors
= (core
->bcBitCount
<= 8) ? 1 << core
->bcBitCount
: 0;
121 return sizeof(BITMAPCOREHEADER
) + colors
*
122 ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBTRIPLE
) : sizeof(WORD
));
124 else /* assume BITMAPINFOHEADER */
126 if (info
->bmiHeader
.biClrUsed
) colors
= min( info
->bmiHeader
.biClrUsed
, 256 );
127 else colors
= info
->bmiHeader
.biBitCount
> 8 ? 0 : 1 << info
->bmiHeader
.biBitCount
;
128 if (info
->bmiHeader
.biCompression
== BI_BITFIELDS
) masks
= 3;
129 size
= max( info
->bmiHeader
.biSize
, sizeof(BITMAPINFOHEADER
) + masks
* sizeof(DWORD
) );
130 return size
+ colors
* ((coloruse
== DIB_RGB_COLORS
) ? sizeof(RGBQUAD
) : sizeof(WORD
));
134 /******************************************************************
137 * Convert an array of POINTS to an array of POINT.
138 * Result must be freed by caller.
140 static POINT
*convert_points( UINT count
, const POINTS
*pts
)
143 POINT
*ret
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*ret
) );
146 for (i
= 0; i
< count
; i
++)
155 /******************************************************************
156 * DeleteMetaFile (GDI32.@)
158 * Delete a memory-based metafile.
161 BOOL WINAPI
DeleteMetaFile( HMETAFILE hmf
)
166 EnterCriticalSection( &metafile_cs
);
167 if ((data
= get_gdi_client_ptr( hmf
, NTGDI_OBJ_METAFILE
)))
169 ret
= NtGdiDeleteClientObj( hmf
);
170 if (ret
) HeapFree( GetProcessHeap(), 0, data
);
172 LeaveCriticalSection( &metafile_cs
);
174 if (!ret
) SetLastError( ERROR_INVALID_HANDLE
);
178 /******************************************************************
181 * Returns a pointer to a memory based METAHEADER read in from file HFILE
184 static METAHEADER
*MF_ReadMetaFile(HANDLE hfile
)
187 DWORD BytesRead
, size
;
189 size
= sizeof(METAHEADER
);
190 mh
= HeapAlloc( GetProcessHeap(), 0, size
);
192 if(ReadFile( hfile
, mh
, size
, &BytesRead
, NULL
) == 0 ||
194 HeapFree( GetProcessHeap(), 0, mh
);
197 if (mh
->mtType
!= METAFILE_MEMORY
|| mh
->mtVersion
!= MFVERSION
||
198 mh
->mtHeaderSize
!= size
/ 2)
200 HeapFree( GetProcessHeap(), 0, mh
);
203 size
= mh
->mtSize
* 2;
204 mh
= HeapReAlloc( GetProcessHeap(), 0, mh
, size
);
206 size
-= sizeof(METAHEADER
);
207 if(ReadFile( hfile
, (char *)mh
+ sizeof(METAHEADER
), size
, &BytesRead
,
210 HeapFree( GetProcessHeap(), 0, mh
);
214 if (mh
->mtType
!= METAFILE_MEMORY
) {
215 WARN("Disk metafile had mtType = %04x\n", mh
->mtType
);
216 mh
->mtType
= METAFILE_MEMORY
;
221 /******************************************************************
222 * GetMetaFileA (GDI32.@)
224 * Read a metafile from a file. Returns handle to a memory-based metafile.
226 HMETAFILE WINAPI
GetMetaFileA( LPCSTR lpFilename
)
231 TRACE("%s\n", lpFilename
);
236 if((hFile
= CreateFileA(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
237 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
240 mh
= MF_ReadMetaFile(hFile
);
243 return MF_Create_HMETAFILE( mh
);
246 /******************************************************************
247 * GetMetaFileW (GDI32.@)
249 HMETAFILE WINAPI
GetMetaFileW( LPCWSTR lpFilename
)
254 TRACE("%s\n", debugstr_w(lpFilename
));
259 if((hFile
= CreateFileW(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
260 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
263 mh
= MF_ReadMetaFile(hFile
);
266 return MF_Create_HMETAFILE( mh
);
270 /* return a copy of the metafile bits, to be freed with HeapFree */
271 static METAHEADER
*get_metafile_bits( HMETAFILE hmf
)
273 METAHEADER
*ret
= NULL
, *metafile
;
275 EnterCriticalSection( &metafile_cs
);
276 if ((metafile
= get_gdi_client_ptr( hmf
, NTGDI_OBJ_METAFILE
)))
278 ret
= HeapAlloc( GetProcessHeap(), 0, metafile
->mtSize
* 2 );
279 if (ret
) memcpy( ret
, metafile
, metafile
->mtSize
* 2 );
281 else SetLastError( ERROR_INVALID_HANDLE
);
282 LeaveCriticalSection( &metafile_cs
);
287 /******************************************************************
288 * CopyMetaFileW (GDI32.@)
290 * Copies the metafile corresponding to hSrcMetaFile to either
291 * a disk file, if a filename is given, or to a new memory based
292 * metafile, if lpFileName is NULL.
295 * hSrcMetaFile [I] handle of metafile to copy
296 * lpFilename [I] filename if copying to a file
299 * Handle to metafile copy on success, NULL on failure.
302 * Copying to disk returns NULL even if successful.
304 HMETAFILE WINAPI
CopyMetaFileW( HMETAFILE hSrcMetaFile
, LPCWSTR lpFilename
)
306 METAHEADER
*mh
= get_metafile_bits( hSrcMetaFile
);
309 TRACE("(%p,%s)\n", hSrcMetaFile
, debugstr_w(lpFilename
));
313 if(lpFilename
) { /* disk based metafile */
315 if((hFile
= CreateFileW(lpFilename
, GENERIC_WRITE
, 0, NULL
,
316 CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
) {
317 HeapFree( GetProcessHeap(), 0, mh
);
320 WriteFile(hFile
, mh
, mh
->mtSize
* 2, &w
, NULL
);
324 return MF_Create_HMETAFILE( mh
);
328 /******************************************************************
329 * CopyMetaFileA (GDI32.@)
333 HMETAFILE WINAPI
CopyMetaFileA( HMETAFILE hSrcMetaFile
, LPCSTR lpFilename
)
335 UNICODE_STRING lpFilenameW
;
338 if (lpFilename
) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW
, lpFilename
);
339 else lpFilenameW
.Buffer
= NULL
;
341 ret
= CopyMetaFileW( hSrcMetaFile
, lpFilenameW
.Buffer
);
342 if (lpFilenameW
.Buffer
)
343 RtlFreeUnicodeString(&lpFilenameW
);
347 /******************************************************************
348 * PlayMetaFile (GDI32.@)
350 * Renders the metafile specified by hmf in the DC specified by
351 * hdc. Returns FALSE on failure, TRUE on success.
354 * hdc [I] handle of DC to render in
355 * hmf [I] handle of metafile to render
361 BOOL WINAPI
PlayMetaFile( HDC hdc
, HMETAFILE hmf
)
363 BOOL metadc
= GetObjectType(hdc
) == OBJ_METADC
;
364 METAHEADER
*mh
= get_metafile_bits( hmf
);
367 unsigned int offset
= 0;
374 if (!mh
) return FALSE
;
379 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
380 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
381 hPal
= GetCurrentObject(hdc
, OBJ_PAL
);
383 hRgn
= NtGdiCreateRectRgn(0, 0, 0, 0);
384 if (!GetClipRgn(hdc
, hRgn
))
391 /* create the handle table */
392 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
393 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
396 HeapFree( GetProcessHeap(), 0, mh
);
400 /* loop through metafile playing records */
401 offset
= mh
->mtHeaderSize
* 2;
402 while (offset
< mh
->mtSize
* 2)
404 mr
= (METARECORD
*)((char *)mh
+ offset
);
405 TRACE("offset=%04x,size=%08lx\n",
407 if (mr
->rdSize
< 3) { /* catch illegal record sizes */
408 TRACE("Entry got size %ld at offset %d, total mf length is %ld\n",
409 mr
->rdSize
,offset
,mh
->mtSize
*2);
413 offset
+= mr
->rdSize
* 2;
414 if (mr
->rdFunction
== META_EOF
) {
415 TRACE("Got META_EOF so stopping\n");
418 PlayMetaFileRecord( hdc
, ht
, mr
, mh
->mtNoObjects
);
424 SelectObject(hdc
, hPen
);
425 SelectObject(hdc
, hBrush
);
426 SelectPalette(hdc
, hPal
, FALSE
);
427 ExtSelectClipRgn(hdc
, hRgn
, RGN_COPY
);
431 /* free objects in handle table */
432 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
433 if(*(ht
->objectHandle
+ i
) != 0)
434 DeleteObject(*(ht
->objectHandle
+ i
));
436 HeapFree( GetProcessHeap(), 0, ht
);
437 HeapFree( GetProcessHeap(), 0, mh
);
441 /******************************************************************
442 * EnumMetaFile (GDI32.@)
444 * Loop through the metafile records in hmf, calling the user-specified
445 * function for each one, stopping when the user's function returns FALSE
446 * (which is considered to be failure)
447 * or when no records are left (which is considered to be success).
450 * TRUE on success, FALSE on failure.
452 BOOL WINAPI
EnumMetaFile(HDC hdc
, HMETAFILE hmf
, MFENUMPROC lpEnumFunc
, LPARAM lpData
)
454 METAHEADER
*mh
= get_metafile_bits( hmf
);
459 unsigned int offset
= 0;
464 TRACE("(%p,%p,%p,%Ix)\n", hdc
, hmf
, lpEnumFunc
, lpData
);
466 if (!mh
) return FALSE
;
468 /* save the current pen, brush and font */
469 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
470 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
471 hFont
= GetCurrentObject(hdc
, OBJ_FONT
);
473 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
474 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
476 /* loop through metafile records */
477 offset
= mh
->mtHeaderSize
* 2;
479 while (offset
< (mh
->mtSize
* 2))
481 mr
= (METARECORD
*)((char *)mh
+ offset
);
482 if(mr
->rdFunction
== META_EOF
) {
483 TRACE("Got META_EOF so stopping\n");
486 TRACE("Calling EnumFunc with record type %x\n",
488 if (!lpEnumFunc( hdc
, ht
, mr
, mh
->mtNoObjects
, lpData
))
494 offset
+= (mr
->rdSize
* 2);
497 /* restore pen, brush and font */
498 SelectObject(hdc
, hBrush
);
499 SelectObject(hdc
, hPen
);
500 SelectObject(hdc
, hFont
);
502 /* free objects in handle table */
503 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
504 if(*(ht
->objectHandle
+ i
) != 0)
505 DeleteObject(*(ht
->objectHandle
+ i
));
507 HeapFree( GetProcessHeap(), 0, ht
);
508 HeapFree( GetProcessHeap(), 0, mh
);
512 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
);
513 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
);
514 /******************************************************************
515 * PlayMetaFileRecord (GDI32.@)
517 * Render a single metafile record specified by *mr in the DC hdc, while
518 * using the handle table *ht, of length handles,
519 * to store metafile objects.
522 * The following metafile records are unimplemented:
524 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
525 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
526 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
528 BOOL WINAPI
PlayMetaFileRecord( HDC hdc
, HANDLETABLE
*ht
, METARECORD
*mr
, UINT handles
)
532 BITMAPINFOHEADER
*infohdr
;
534 TRACE("(%p %p %p %u) function %04x\n", hdc
, ht
, mr
, handles
, mr
->rdFunction
);
536 switch (mr
->rdFunction
)
541 case META_DELETEOBJECT
:
542 DeleteObject(*(ht
->objectHandle
+ mr
->rdParm
[0]));
543 *(ht
->objectHandle
+ mr
->rdParm
[0]) = 0;
546 case META_SETBKCOLOR
:
547 SetBkColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
551 SetBkMode(hdc
, mr
->rdParm
[0]);
554 case META_SETMAPMODE
:
555 SetMapMode(hdc
, mr
->rdParm
[0]);
559 SetROP2(hdc
, mr
->rdParm
[0]);
563 SetRelAbs(hdc
, mr
->rdParm
[0]);
566 case META_SETPOLYFILLMODE
:
567 SetPolyFillMode(hdc
, mr
->rdParm
[0]);
570 case META_SETSTRETCHBLTMODE
:
571 SetStretchBltMode(hdc
, mr
->rdParm
[0]);
574 case META_SETTEXTCOLOR
:
575 SetTextColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
578 case META_SETWINDOWORG
:
579 SetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
582 case META_SETWINDOWEXT
:
583 SetWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
586 case META_SETVIEWPORTORG
:
587 SetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
590 case META_SETVIEWPORTEXT
:
591 SetViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
594 case META_OFFSETWINDOWORG
:
595 OffsetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
598 case META_SCALEWINDOWEXT
:
599 ScaleWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
600 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
603 case META_OFFSETVIEWPORTORG
:
604 OffsetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
607 case META_SCALEVIEWPORTEXT
:
608 ScaleViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
609 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
613 LineTo(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
617 MoveToEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
620 case META_EXCLUDECLIPRECT
:
621 ExcludeClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
622 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
625 case META_INTERSECTCLIPRECT
:
626 IntersectClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
627 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
631 Arc(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
632 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
633 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
634 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
638 Ellipse(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
639 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
643 FloodFill(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
644 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
648 Pie(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
649 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
650 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
651 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
655 Rectangle(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
656 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
660 RoundRect(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
661 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
662 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
666 PatBlt(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
667 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
668 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
676 SetPixel(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
677 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
680 case META_OFFSETCLIPRGN
:
681 OffsetClipRgn( hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
686 TextOutA(hdc
, (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 2],
687 (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 1],
688 (char *)(mr
->rdParm
+ 1), s1
);
692 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
694 Polygon(hdc
, pt
, mr
->rdParm
[0]);
695 HeapFree( GetProcessHeap(), 0, pt
);
699 case META_POLYPOLYGON
:
702 SHORT
*counts
= (SHORT
*)(mr
->rdParm
+ 1);
704 for (i
= total
= 0; i
< mr
->rdParm
[0]; i
++) total
+= counts
[i
];
705 pt
= convert_points( total
, (POINTS
*)(counts
+ mr
->rdParm
[0]) );
708 INT
*cnt32
= HeapAlloc( GetProcessHeap(), 0, mr
->rdParm
[0] * sizeof(*cnt32
) );
711 for (i
= 0; i
< mr
->rdParm
[0]; i
++) cnt32
[i
] = counts
[i
];
712 PolyPolygon( hdc
, pt
, cnt32
, mr
->rdParm
[0]);
713 HeapFree( GetProcessHeap(), 0, cnt32
);
716 HeapFree( GetProcessHeap(), 0, pt
);
721 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
723 Polyline( hdc
, pt
, mr
->rdParm
[0] );
724 HeapFree( GetProcessHeap(), 0, pt
);
729 RestoreDC(hdc
, (SHORT
)mr
->rdParm
[0]);
732 case META_SELECTOBJECT
:
733 SelectObject(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
737 Chord(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
738 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
739 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
740 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
743 case META_CREATEPATTERNBRUSH
:
744 switch (mr
->rdParm
[0])
747 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
748 MF_AddHandle(ht
, handles
,
749 CreatePatternBrush(CreateBitmap(infohdr
->biWidth
,
754 (sizeof(BITMAPINFOHEADER
) / 2) + 4)));
758 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
759 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( infohdr
, mr
->rdParm
[1] ));
763 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
769 case META_CREATEPENINDIRECT
:
772 pen
.lopnStyle
= mr
->rdParm
[0];
773 pen
.lopnWidth
.x
= (SHORT
)mr
->rdParm
[1];
774 pen
.lopnWidth
.y
= (SHORT
)mr
->rdParm
[2];
775 pen
.lopnColor
= MAKELONG( mr
->rdParm
[3], mr
->rdParm
[4] );
776 MF_AddHandle(ht
, handles
, CreatePenIndirect( &pen
));
780 case META_CREATEFONTINDIRECT
:
783 font
.lfHeight
= (SHORT
)mr
->rdParm
[0];
784 font
.lfWidth
= (SHORT
)mr
->rdParm
[1];
785 font
.lfEscapement
= (SHORT
)mr
->rdParm
[2];
786 font
.lfOrientation
= (SHORT
)mr
->rdParm
[3];
787 font
.lfWeight
= (SHORT
)mr
->rdParm
[4];
788 font
.lfItalic
= LOBYTE(mr
->rdParm
[5]);
789 font
.lfUnderline
= HIBYTE(mr
->rdParm
[5]);
790 font
.lfStrikeOut
= LOBYTE(mr
->rdParm
[6]);
791 font
.lfCharSet
= HIBYTE(mr
->rdParm
[6]);
792 font
.lfOutPrecision
= LOBYTE(mr
->rdParm
[7]);
793 font
.lfClipPrecision
= HIBYTE(mr
->rdParm
[7]);
794 font
.lfQuality
= LOBYTE(mr
->rdParm
[8]);
795 font
.lfPitchAndFamily
= HIBYTE(mr
->rdParm
[8]);
796 memcpy( font
.lfFaceName
, mr
->rdParm
+ 9, LF_FACESIZE
);
797 MF_AddHandle(ht
, handles
, CreateFontIndirectA( &font
));
801 case META_CREATEBRUSHINDIRECT
:
804 brush
.lbStyle
= mr
->rdParm
[0];
805 brush
.lbColor
= MAKELONG( mr
->rdParm
[1], mr
->rdParm
[2] );
806 brush
.lbHatch
= mr
->rdParm
[3];
807 MF_AddHandle(ht
, handles
, CreateBrushIndirect( &brush
));
811 case META_CREATEPALETTE
:
812 MF_AddHandle(ht
, handles
, CreatePalette((LPLOGPALETTE
)mr
->rdParm
));
815 case META_SETTEXTALIGN
:
816 SetTextAlign(hdc
, mr
->rdParm
[0]);
819 case META_SELECTPALETTE
:
820 SelectPalette( hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]), mr
->rdParm
[0] );
823 case META_SETMAPPERFLAGS
:
824 SetMapperFlags(hdc
, MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
827 case META_REALIZEPALETTE
:
832 switch (mr
->rdParm
[0]) {
833 case GETSCALINGFACTOR
: /* get function ... would just NULL dereference */
834 case GETPHYSPAGESIZE
:
835 case GETPRINTINGOFFSET
:
838 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
841 Escape(hdc
, mr
->rdParm
[0], mr
->rdParm
[1], (LPCSTR
)&mr
->rdParm
[2], NULL
);
844 case META_EXTTEXTOUT
:
845 MF_Play_MetaExtTextOut( hdc
, mr
);
848 case META_STRETCHDIB
:
850 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[11]);
851 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, mr
->rdParm
[2] );
852 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[10], (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
853 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
854 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], bits
, info
,
855 mr
->rdParm
[2],MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
859 case META_DIBSTRETCHBLT
:
861 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[10]);
862 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, DIB_RGB_COLORS
);
863 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
864 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
865 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2], bits
, info
,
866 DIB_RGB_COLORS
,MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
870 case META_STRETCHBLT
:
872 HDC hdcSrc
= NtGdiCreateCompatibleDC( hdc
);
873 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[10], /*Width */
874 mr
->rdParm
[11], /*Height*/
875 mr
->rdParm
[13], /*Planes*/
876 mr
->rdParm
[14], /*BitsPixel*/
877 &mr
->rdParm
[15]); /*bits*/
878 SelectObject(hdcSrc
,hbitmap
);
879 StretchBlt(hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
880 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
881 hdcSrc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
882 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
883 MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
890 HDC hdcSrc
= NtGdiCreateCompatibleDC( hdc
);
891 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[7]/*Width */,
892 mr
->rdParm
[8]/*Height*/,
893 mr
->rdParm
[10]/*Planes*/,
894 mr
->rdParm
[11]/*BitsPixel*/,
895 &mr
->rdParm
[12]/*bits*/);
896 SelectObject(hdcSrc
,hbitmap
);
897 BitBlt(hdc
,(SHORT
)mr
->rdParm
[6],(SHORT
)mr
->rdParm
[5],
898 (SHORT
)mr
->rdParm
[4],(SHORT
)mr
->rdParm
[3],
899 hdcSrc
, (SHORT
)mr
->rdParm
[2],(SHORT
)mr
->rdParm
[1],
900 MAKELONG(0,mr
->rdParm
[0]));
905 case META_CREATEREGION
:
907 HRGN hrgn
= NtGdiCreateRectRgn(0,0,0,0);
909 MF_Play_MetaCreateRegion(mr
, hrgn
);
910 MF_AddHandle(ht
, handles
, hrgn
);
914 case META_FILLREGION
:
915 FillRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]),
916 *(ht
->objectHandle
+ mr
->rdParm
[0]));
919 case META_FRAMEREGION
:
920 FrameRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[3]),
921 *(ht
->objectHandle
+ mr
->rdParm
[2]),
922 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
925 case META_INVERTREGION
:
926 InvertRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
929 case META_PAINTREGION
:
930 PaintRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
933 case META_SELECTCLIPREGION
:
937 if (mr
->rdParm
[0]) hrgn
= *(ht
->objectHandle
+ mr
->rdParm
[0]);
938 SelectClipRgn(hdc
, hrgn
);
942 case META_DIBCREATEPATTERNBRUSH
:
943 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
944 but there's no difference */
945 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( mr
->rdParm
+ 2, mr
->rdParm
[1] ));
949 /* In practice I've found that there are two layouts for
950 META_DIBBITBLT, one (the first here) is the usual one when a src
951 dc is actually passed to it, the second occurs when the src dc is
952 passed in as NULL to the creating BitBlt. As the second case has
953 no dib, a size check will suffice to distinguish.
955 Caolan.McNamara@ul.ie */
957 if (mr
->rdSize
> 12) {
958 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[8]);
959 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size(info
, mr
->rdParm
[0]);
961 StretchDIBits(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
962 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
963 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4], bits
, info
,
964 DIB_RGB_COLORS
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
966 else /* equivalent to a PatBlt */
967 PatBlt(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
968 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
969 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
972 case META_SETTEXTCHAREXTRA
:
973 SetTextCharacterExtra(hdc
, (SHORT
)mr
->rdParm
[0]);
976 case META_SETTEXTJUSTIFICATION
:
977 SetTextJustification(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
980 case META_EXTFLOODFILL
:
981 ExtFloodFill(hdc
, (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
982 MAKELONG(mr
->rdParm
[1], mr
->rdParm
[2]),
986 case META_SETDIBTODEV
:
988 BITMAPINFO
*info
= (BITMAPINFO
*) &(mr
->rdParm
[9]);
989 char *bits
= (char *)info
+ bitmap_info_size( info
, mr
->rdParm
[0] );
990 SetDIBitsToDevice(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
991 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
992 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
993 mr
->rdParm
[2], mr
->rdParm
[1], bits
, info
,
998 #define META_UNIMP(x) case x: \
999 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1001 META_UNIMP(META_DRAWTEXT
)
1002 META_UNIMP(META_ANIMATEPALETTE
)
1003 META_UNIMP(META_SETPALENTRIES
)
1004 META_UNIMP(META_RESIZEPALETTE
)
1005 META_UNIMP(META_RESETDC
)
1006 META_UNIMP(META_STARTDOC
)
1007 META_UNIMP(META_STARTPAGE
)
1008 META_UNIMP(META_ENDPAGE
)
1009 META_UNIMP(META_ABORTDOC
)
1010 META_UNIMP(META_ENDDOC
)
1011 META_UNIMP(META_CREATEBRUSH
)
1012 META_UNIMP(META_CREATEBITMAPINDIRECT
)
1013 META_UNIMP(META_CREATEBITMAP
)
1017 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr
->rdFunction
);
1023 /******************************************************************
1024 * SetMetaFileBitsEx (GDI32.@)
1026 * Create a metafile from raw data. No checking of the data is performed.
1027 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1030 * size [I] size of metafile, in bytes
1031 * lpData [I] pointer to metafile data
1034 * Success: Handle to metafile.
1037 HMETAFILE WINAPI
SetMetaFileBitsEx( UINT size
, const BYTE
*lpData
)
1039 const METAHEADER
*mh_in
= (const METAHEADER
*)lpData
;
1042 if (size
& 1) return 0;
1044 if (!size
|| mh_in
->mtType
!= METAFILE_MEMORY
|| mh_in
->mtVersion
!= MFVERSION
||
1045 mh_in
->mtHeaderSize
!= sizeof(METAHEADER
) / 2)
1047 SetLastError(ERROR_INVALID_DATA
);
1051 mh_out
= HeapAlloc( GetProcessHeap(), 0, size
);
1054 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1058 memcpy(mh_out
, mh_in
, size
);
1059 mh_out
->mtSize
= size
/ 2;
1060 return MF_Create_HMETAFILE(mh_out
);
1063 /*****************************************************************
1064 * GetMetaFileBitsEx (GDI32.@)
1066 * Get raw metafile data.
1068 * Copies the data from metafile _hmf_ into the buffer _buf_.
1072 * nSize [I] size of buf
1073 * buf [O] buffer to receive raw metafile data
1076 * If _buf_ is zero, returns size of buffer required. Otherwise,
1077 * returns number of bytes copied.
1079 UINT WINAPI
GetMetaFileBitsEx( HMETAFILE hmf
, UINT buf_size
, void *buf
)
1081 METAHEADER
*metafile
;
1084 TRACE( "(%p,%d,%p)\n", hmf
, buf_size
, buf
);
1086 EnterCriticalSection( &metafile_cs
);
1087 if ((metafile
= get_gdi_client_ptr( hmf
, NTGDI_OBJ_METAFILE
)))
1089 size
= metafile
->mtSize
* 2;
1092 if(size
> buf_size
) size
= buf_size
;
1093 memmove( buf
, metafile
, size
);
1096 else SetLastError( ERROR_INVALID_HANDLE
);
1097 LeaveCriticalSection( &metafile_cs
);
1099 TRACE( "returning size %d\n", size
);
1103 /******************************************************************
1106 * Helper for GetWinMetaFileBits
1108 * Add the MFCOMMENT record[s] which is essentially a copy
1109 * of the original emf.
1111 static BOOL
add_mf_comment(HDC hdc
, HENHMETAFILE emf
)
1113 DWORD size
= GetEnhMetaFileBits(emf
, 0, NULL
), i
;
1114 BYTE
*bits
, *chunk_data
;
1115 emf_in_wmf_comment
*chunk
= NULL
;
1117 static const DWORD max_chunk_size
= 0x2000;
1119 if(!size
) return FALSE
;
1120 chunk_data
= bits
= HeapAlloc(GetProcessHeap(), 0, size
);
1121 if(!bits
) return FALSE
;
1122 if(!GetEnhMetaFileBits(emf
, size
, bits
)) goto end
;
1124 chunk
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment
, emf_data
[max_chunk_size
]));
1125 if(!chunk
) goto end
;
1127 chunk
->comment_id
= WMFC_MAGIC
;
1128 chunk
->comment_type
= 0x1;
1129 chunk
->version
= 0x00010000;
1130 chunk
->checksum
= 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1132 chunk
->num_chunks
= (size
+ max_chunk_size
- 1) / max_chunk_size
;
1133 chunk
->chunk_size
= max_chunk_size
;
1134 chunk
->remaining_size
= size
;
1135 chunk
->emf_size
= size
;
1137 for(i
= 0; i
< chunk
->num_chunks
; i
++)
1139 if(i
== chunk
->num_chunks
- 1) /* last chunk */
1140 chunk
->chunk_size
= chunk
->remaining_size
;
1142 chunk
->remaining_size
-= chunk
->chunk_size
;
1143 memcpy(chunk
->emf_data
, chunk_data
, chunk
->chunk_size
);
1144 chunk_data
+= chunk
->chunk_size
;
1146 if(!Escape(hdc
, MFCOMMENT
, FIELD_OFFSET(emf_in_wmf_comment
, emf_data
[chunk
->chunk_size
]), (char*)chunk
, NULL
))
1151 HeapFree(GetProcessHeap(), 0, chunk
);
1152 HeapFree(GetProcessHeap(), 0, bits
);
1156 /*******************************************************************
1159 * Behaves somewhat differently to MulDiv when the answer is -ve
1160 * and also rounds n.5 towards zero
1162 static INT
muldiv(INT m1
, INT m2
, INT d
)
1166 ret
= ((LONGLONG
)m1
* m2
+ d
/2) / d
; /* Always add d/2 even if ret will be -ve */
1168 if((LONGLONG
)m1
* m2
* 2 == (2 * ret
- 1) * d
) /* If the answer is exactly n.5 round towards zero */
1176 /******************************************************************
1179 * Helper for GetWinMetaFileBits
1181 * Add the SetWindowOrg and SetWindowExt records
1183 static BOOL
set_window(HDC hdc
, HENHMETAFILE emf
, HDC ref_dc
, INT map_mode
)
1185 ENHMETAHEADER header
;
1186 INT horz_res
, vert_res
, horz_size
, vert_size
;
1189 if(!GetEnhMetaFileHeader(emf
, sizeof(header
), &header
)) return FALSE
;
1191 horz_res
= GetDeviceCaps(ref_dc
, HORZRES
);
1192 vert_res
= GetDeviceCaps(ref_dc
, VERTRES
);
1193 horz_size
= GetDeviceCaps(ref_dc
, HORZSIZE
);
1194 vert_size
= GetDeviceCaps(ref_dc
, VERTSIZE
);
1200 case MM_ANISOTROPIC
:
1201 pt
.y
= muldiv(header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1202 pt
.x
= muldiv(header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1205 pt
.y
= muldiv(-header
.rclFrame
.top
, 1, 10) + 1;
1206 pt
.x
= muldiv( header
.rclFrame
.left
, 1, 10);
1209 pt
.y
= -header
.rclFrame
.top
+ 1;
1210 pt
.x
= (header
.rclFrame
.left
>= 0) ? header
.rclFrame
.left
: header
.rclFrame
.left
+ 1; /* See the tests */
1213 pt
.y
= muldiv(-header
.rclFrame
.top
, 10, 254) + 1;
1214 pt
.x
= muldiv( header
.rclFrame
.left
, 10, 254);
1217 pt
.y
= muldiv(-header
.rclFrame
.top
, 100, 254) + 1;
1218 pt
.x
= muldiv( header
.rclFrame
.left
, 100, 254);
1221 pt
.y
= muldiv(-header
.rclFrame
.top
, 72 * 20, 2540) + 1;
1222 pt
.x
= muldiv( header
.rclFrame
.left
, 72 * 20, 2540);
1225 WARN("Unknown map mode %d\n", map_mode
);
1228 SetWindowOrgEx(hdc
, pt
.x
, pt
.y
, NULL
);
1230 pt
.x
= muldiv(header
.rclFrame
.right
- header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1231 pt
.y
= muldiv(header
.rclFrame
.bottom
- header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1232 SetWindowExtEx(hdc
, pt
.x
, pt
.y
, NULL
);
1236 /******************************************************************
1237 * GetWinMetaFileBits [GDI32.@]
1239 UINT WINAPI
GetWinMetaFileBits(HENHMETAFILE hemf
,
1240 UINT cbBuffer
, LPBYTE lpbBuffer
,
1241 INT map_mode
, HDC hdcRef
)
1245 UINT ret
, full_size
;
1248 NtGdiGetAppClipBox(hdcRef
, &rc
);
1250 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf
, cbBuffer
, lpbBuffer
,
1251 map_mode
, hdcRef
, wine_dbgstr_rect(&rc
));
1253 hdcmf
= CreateMetaFileW(NULL
);
1255 add_mf_comment(hdcmf
, hemf
);
1256 SetMapMode(hdcmf
, map_mode
);
1257 if(!set_window(hdcmf
, hemf
, hdcRef
, map_mode
))
1260 PlayEnhMetaFile(hdcmf
, hemf
, &rc
);
1261 hmf
= CloseMetaFile(hdcmf
);
1262 full_size
= GetMetaFileBitsEx(hmf
, 0, NULL
);
1263 ret
= GetMetaFileBitsEx(hmf
, cbBuffer
, lpbBuffer
);
1264 DeleteMetaFile(hmf
);
1266 if(ret
&& ret
== full_size
&& lpbBuffer
) /* fixup checksum, but only if retrieving all of the bits */
1269 METARECORD
*comment_rec
= (METARECORD
*)(lpbBuffer
+ sizeof(METAHEADER
));
1272 for(i
= 0; i
< full_size
/ 2; i
++)
1273 checksum
+= ((WORD
*)lpbBuffer
)[i
];
1274 comment_rec
->rdParm
[8] = ~checksum
+ 1;
1279 DeleteMetaFile(CloseMetaFile(hdcmf
));
1283 /******************************************************************
1284 * MF_Play_MetaCreateRegion
1286 * Handles META_CREATEREGION for PlayMetaFileRecord().
1288 * The layout of the record looks something like this:
1293 * 2 Looks like a handle? - not constant
1295 * 4 Total number of bytes
1296 * 5 No. of separate bands = n [see below]
1297 * 6 Largest number of x co-ords in a band
1298 * 7-10 Bounding box x1 y1 x2 y2
1301 * Regions are divided into bands that are uniform in the
1302 * y-direction. Each band consists of pairs of on/off x-coords and is
1304 * m y0 y1 x1 x2 x3 ... xm m
1305 * into successive rdParm[]s.
1307 * This is probably just a dump of the internal RGNOBJ?
1313 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
)
1318 HRGN hrgn2
= NtGdiCreateRectRgn( 0, 0, 0, 0 );
1320 for(band
= 0, start
= &(mr
->rdParm
[11]); band
< mr
->rdParm
[5];
1321 band
++, start
= end
+ 1) {
1322 if(*start
/ 2 != (*start
+ 1) / 2) {
1323 WARN("Delimiter not even.\n");
1324 DeleteObject( hrgn2
);
1328 end
= start
+ *start
+ 3;
1329 if(end
> (WORD
*)mr
+ mr
->rdSize
) {
1330 WARN("End points outside record.\n");
1331 DeleteObject( hrgn2
);
1335 if(*start
!= *end
) {
1336 WARN("Mismatched delimiters.\n");
1337 DeleteObject( hrgn2
);
1341 y0
= *(INT16
*)(start
+ 1);
1342 y1
= *(INT16
*)(start
+ 2);
1343 for(pair
= 0; pair
< *start
/ 2; pair
++) {
1344 NtGdiSetRectRgn( hrgn2
, *(INT16
*)(start
+ 3 + 2*pair
), y0
,
1345 *(INT16
*)(start
+ 4 + 2*pair
), y1
);
1346 NtGdiCombineRgn( hrgn
, hrgn
, hrgn2
, RGN_OR
);
1349 DeleteObject( hrgn2
);
1354 /******************************************************************
1355 * MF_Play_MetaExtTextOut
1357 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1360 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
)
1369 BOOL isrect
= mr
->rdParm
[3] & (ETO_OPAQUE
| ETO_CLIPPED
);
1371 s1
= mr
->rdParm
[2]; /* String length */
1372 len
= sizeof(METARECORD
) + (((s1
+ 1) >> 1) * 2) + 2 * sizeof(short)
1373 + sizeof(UINT16
) + (isrect
? 4 * sizeof(SHORT
) : 0);
1374 /* rec len without dx array */
1376 sot
= (LPSTR
)&mr
->rdParm
[4]; /* start_of_text */
1379 rect
.left
= (SHORT
)mr
->rdParm
[4];
1380 rect
.top
= (SHORT
)mr
->rdParm
[5];
1381 rect
.right
= (SHORT
)mr
->rdParm
[6];
1382 rect
.bottom
= (SHORT
)mr
->rdParm
[7];
1383 sot
+= 4 * sizeof(SHORT
); /* there is a rectangle, so add offset */
1386 if (mr
->rdSize
== len
/ 2)
1387 dxx
= NULL
; /* determine if array is present */
1389 if (mr
->rdSize
== (len
+ s1
* sizeof(INT16
)) / 2)
1391 dxx
= (SHORT
*)(sot
+(((s1
+1)>>1)*2));
1392 dx
= HeapAlloc( GetProcessHeap(), 0, s1
*sizeof(INT
));
1393 if (dx
) for (i
= 0; i
< s1
; i
++) dx
[i
] = dxx
[i
];
1396 TRACE("%s len: %ld\n", sot
, mr
->rdSize
);
1397 WARN("Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1398 len
, s1
, mr
->rdSize
, mr
->rdParm
[3]);
1399 dxx
= NULL
; /* shouldn't happen -- but if, we continue with NULL */
1402 (SHORT
)mr
->rdParm
[1], /* X position */
1403 (SHORT
)mr
->rdParm
[0], /* Y position */
1404 mr
->rdParm
[3], /* options */
1405 &rect
, /* rectangle */
1407 s1
, dx
); /* length, dx array */
1410 TRACE("%s len: %ld dx0: %d\n", sot
, mr
->rdSize
, dx
[0]);
1411 HeapFree( GetProcessHeap(), 0, dx
);