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.
60 #include "wine/winternl.h"
61 #include "gdi_private.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(metafile
);
76 /******************************************************************
79 * Add a handle to an external handle table and return the index
81 static int MF_AddHandle(HANDLETABLE
*ht
, UINT htlen
, HGDIOBJ hobj
)
85 for (i
= 0; i
< htlen
; i
++)
87 if (*(ht
->objectHandle
+ i
) == 0)
89 *(ht
->objectHandle
+ i
) = hobj
;
97 /******************************************************************
98 * MF_Create_HMETATFILE
100 * Creates a (32 bit) HMETAFILE object from a METAHEADER
102 * HMETAFILEs are GDI objects.
104 HMETAFILE
MF_Create_HMETAFILE(METAHEADER
*mh
)
106 return alloc_gdi_handle( mh
, OBJ_METAFILE
, NULL
);
109 /******************************************************************
112 * Convert an array of POINTS to an array of POINT.
113 * Result must be freed by caller.
115 static POINT
*convert_points( UINT count
, const POINTS
*pts
)
118 POINT
*ret
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*ret
) );
121 for (i
= 0; i
< count
; i
++)
130 /******************************************************************
131 * DeleteMetaFile (GDI32.@)
133 * Delete a memory-based metafile.
136 BOOL WINAPI
DeleteMetaFile( HMETAFILE hmf
)
138 METAHEADER
*mh
= free_gdi_handle( hmf
);
139 if (!mh
) return FALSE
;
140 return HeapFree( GetProcessHeap(), 0, mh
);
143 /******************************************************************
146 * Returns a pointer to a memory based METAHEADER read in from file HFILE
149 static METAHEADER
*MF_ReadMetaFile(HANDLE hfile
)
152 DWORD BytesRead
, size
;
154 size
= sizeof(METAHEADER
);
155 mh
= HeapAlloc( GetProcessHeap(), 0, size
);
157 if(ReadFile( hfile
, mh
, size
, &BytesRead
, NULL
) == 0 ||
159 HeapFree( GetProcessHeap(), 0, mh
);
162 if (mh
->mtType
!= METAFILE_MEMORY
|| mh
->mtVersion
!= MFVERSION
||
163 mh
->mtHeaderSize
!= size
/ 2)
165 HeapFree( GetProcessHeap(), 0, mh
);
168 size
= mh
->mtSize
* 2;
169 mh
= HeapReAlloc( GetProcessHeap(), 0, mh
, size
);
171 size
-= sizeof(METAHEADER
);
172 if(ReadFile( hfile
, (char *)mh
+ sizeof(METAHEADER
), size
, &BytesRead
,
175 HeapFree( GetProcessHeap(), 0, mh
);
179 if (mh
->mtType
!= METAFILE_MEMORY
) {
180 WARN("Disk metafile had mtType = %04x\n", mh
->mtType
);
181 mh
->mtType
= METAFILE_MEMORY
;
186 /******************************************************************
187 * GetMetaFileA (GDI32.@)
189 * Read a metafile from a file. Returns handle to a memory-based metafile.
191 HMETAFILE WINAPI
GetMetaFileA( LPCSTR lpFilename
)
196 TRACE("%s\n", lpFilename
);
201 if((hFile
= CreateFileA(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
202 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
205 mh
= MF_ReadMetaFile(hFile
);
208 return MF_Create_HMETAFILE( mh
);
211 /******************************************************************
212 * GetMetaFileW (GDI32.@)
214 HMETAFILE WINAPI
GetMetaFileW( LPCWSTR lpFilename
)
219 TRACE("%s\n", debugstr_w(lpFilename
));
224 if((hFile
= CreateFileW(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
225 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
228 mh
= MF_ReadMetaFile(hFile
);
231 return MF_Create_HMETAFILE( mh
);
235 /******************************************************************
236 * MF_LoadDiskBasedMetaFile
238 * Creates a new memory-based metafile from a disk-based one.
240 static METAHEADER
*MF_LoadDiskBasedMetaFile(METAHEADER
*mh
)
246 if(mh
->mtType
!= METAFILE_DISK
) {
247 ERR("Not a disk based metafile\n");
250 mhd
= (METAHEADERDISK
*)((char *)mh
+ sizeof(METAHEADER
));
252 if((hfile
= CreateFileA(mhd
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
253 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
254 WARN("Can't open file of disk based metafile\n");
257 mh2
= MF_ReadMetaFile(hfile
);
262 /******************************************************************
263 * MF_CreateMetaHeaderDisk
265 * Take a memory based METAHEADER and change it to a disk based METAHEADER
266 * associated with filename. Note: Trashes contents of old one.
268 METAHEADER
*MF_CreateMetaHeaderDisk(METAHEADER
*mh
, LPCVOID filename
, BOOL uni
)
272 mh
= HeapReAlloc( GetProcessHeap(), 0, mh
,
273 sizeof(METAHEADER
) + sizeof(METAHEADERDISK
));
274 mh
->mtType
= METAFILE_DISK
;
275 mhd
= (METAHEADERDISK
*)((char *)mh
+ sizeof(METAHEADER
));
278 WideCharToMultiByte(CP_ACP
, 0, filename
, -1,
279 mhd
->filename
, sizeof mhd
->filename
, NULL
, NULL
);
281 lstrcpynA( mhd
->filename
, filename
, sizeof mhd
->filename
);
285 /* return a copy of the metafile bits, to be freed with HeapFree */
286 static METAHEADER
*get_metafile_bits( HMETAFILE hmf
)
288 METAHEADER
*ret
, *mh
= GDI_GetObjPtr( hmf
, OBJ_METAFILE
);
290 if (!mh
) return NULL
;
292 if (mh
->mtType
!= METAFILE_DISK
)
294 ret
= HeapAlloc( GetProcessHeap(), 0, mh
->mtSize
* 2 );
295 if (ret
) memcpy( ret
, mh
, mh
->mtSize
* 2 );
297 else ret
= MF_LoadDiskBasedMetaFile( mh
);
299 GDI_ReleaseObj( hmf
);
303 /******************************************************************
304 * CopyMetaFileW (GDI32.@)
306 * Copies the metafile corresponding to hSrcMetaFile to either
307 * a disk file, if a filename is given, or to a new memory based
308 * metafile, if lpFileName is NULL.
311 * hSrcMetaFile [I] handle of metafile to copy
312 * lpFilename [I] filename if copying to a file
315 * Handle to metafile copy on success, NULL on failure.
318 * Copying to disk returns NULL even if successful.
320 HMETAFILE WINAPI
CopyMetaFileW( HMETAFILE hSrcMetaFile
, LPCWSTR lpFilename
)
322 METAHEADER
*mh
= get_metafile_bits( hSrcMetaFile
);
325 TRACE("(%p,%s)\n", hSrcMetaFile
, debugstr_w(lpFilename
));
329 if(lpFilename
) { /* disk based metafile */
331 if((hFile
= CreateFileW(lpFilename
, GENERIC_WRITE
, 0, NULL
,
332 CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
) {
333 HeapFree( GetProcessHeap(), 0, mh
);
336 WriteFile(hFile
, mh
, mh
->mtSize
* 2, &w
, NULL
);
340 return MF_Create_HMETAFILE( mh
);
344 /******************************************************************
345 * CopyMetaFileA (GDI32.@)
349 HMETAFILE WINAPI
CopyMetaFileA( HMETAFILE hSrcMetaFile
, LPCSTR lpFilename
)
351 UNICODE_STRING lpFilenameW
;
354 if (lpFilename
) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW
, lpFilename
);
355 else lpFilenameW
.Buffer
= NULL
;
357 ret
= CopyMetaFileW( hSrcMetaFile
, lpFilenameW
.Buffer
);
358 if (lpFilenameW
.Buffer
)
359 RtlFreeUnicodeString(&lpFilenameW
);
363 /******************************************************************
364 * PlayMetaFile (GDI32.@)
366 * Renders the metafile specified by hmf in the DC specified by
367 * hdc. Returns FALSE on failure, TRUE on success.
370 * hdc [I] handle of DC to render in
371 * hmf [I] handle of metafile to render
377 BOOL WINAPI
PlayMetaFile( HDC hdc
, HMETAFILE hmf
)
379 METAHEADER
*mh
= get_metafile_bits( hmf
);
382 unsigned int offset
= 0;
389 if (!mh
) return FALSE
;
392 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
393 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
394 hPal
= GetCurrentObject(hdc
, OBJ_PAL
);
396 hRgn
= CreateRectRgn(0, 0, 0, 0);
397 if (!GetClipRgn(hdc
, hRgn
))
403 /* create the handle table */
404 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
405 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
408 HeapFree( GetProcessHeap(), 0, mh
);
412 /* loop through metafile playing records */
413 offset
= mh
->mtHeaderSize
* 2;
414 while (offset
< mh
->mtSize
* 2)
416 mr
= (METARECORD
*)((char *)mh
+ offset
);
417 TRACE("offset=%04x,size=%08x\n",
419 if (mr
->rdSize
< 3) { /* catch illegal record sizes */
420 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
421 mr
->rdSize
,offset
,mh
->mtSize
*2);
425 offset
+= mr
->rdSize
* 2;
426 if (mr
->rdFunction
== META_EOF
) {
427 TRACE("Got META_EOF so stopping\n");
430 PlayMetaFileRecord( hdc
, ht
, mr
, mh
->mtNoObjects
);
434 SelectObject(hdc
, hPen
);
435 SelectObject(hdc
, hBrush
);
436 SelectPalette(hdc
, hPal
, FALSE
);
437 ExtSelectClipRgn(hdc
, hRgn
, RGN_COPY
);
440 /* free objects in handle table */
441 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
442 if(*(ht
->objectHandle
+ i
) != 0)
443 DeleteObject(*(ht
->objectHandle
+ i
));
445 HeapFree( GetProcessHeap(), 0, ht
);
446 HeapFree( GetProcessHeap(), 0, mh
);
450 /******************************************************************
451 * EnumMetaFile (GDI32.@)
453 * Loop through the metafile records in hmf, calling the user-specified
454 * function for each one, stopping when the user's function returns FALSE
455 * (which is considered to be failure)
456 * or when no records are left (which is considered to be success).
459 * TRUE on success, FALSE on failure.
461 BOOL WINAPI
EnumMetaFile(HDC hdc
, HMETAFILE hmf
, MFENUMPROC lpEnumFunc
, LPARAM lpData
)
463 METAHEADER
*mh
= get_metafile_bits( hmf
);
468 unsigned int offset
= 0;
473 TRACE("(%p,%p,%p,%lx)\n", hdc
, hmf
, lpEnumFunc
, lpData
);
475 if (!mh
) return FALSE
;
477 /* save the current pen, brush and font */
478 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
479 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
480 hFont
= GetCurrentObject(hdc
, OBJ_FONT
);
482 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
483 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
485 /* loop through metafile records */
486 offset
= mh
->mtHeaderSize
* 2;
488 while (offset
< (mh
->mtSize
* 2))
490 mr
= (METARECORD
*)((char *)mh
+ offset
);
491 if(mr
->rdFunction
== META_EOF
) {
492 TRACE("Got META_EOF so stopping\n");
495 TRACE("Calling EnumFunc with record type %x\n",
497 if (!lpEnumFunc( hdc
, ht
, mr
, mh
->mtNoObjects
, lpData
))
503 offset
+= (mr
->rdSize
* 2);
506 /* restore pen, brush and font */
507 SelectObject(hdc
, hBrush
);
508 SelectObject(hdc
, hPen
);
509 SelectObject(hdc
, hFont
);
511 /* free objects in handle table */
512 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
513 if(*(ht
->objectHandle
+ i
) != 0)
514 DeleteObject(*(ht
->objectHandle
+ i
));
516 HeapFree( GetProcessHeap(), 0, ht
);
517 HeapFree( GetProcessHeap(), 0, mh
);
521 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
);
522 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
);
523 /******************************************************************
524 * PlayMetaFileRecord (GDI32.@)
526 * Render a single metafile record specified by *mr in the DC hdc, while
527 * using the handle table *ht, of length handles,
528 * to store metafile objects.
531 * The following metafile records are unimplemented:
533 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
534 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
535 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
537 BOOL WINAPI
PlayMetaFileRecord( HDC hdc
, HANDLETABLE
*ht
, METARECORD
*mr
, UINT handles
)
541 BITMAPINFOHEADER
*infohdr
;
543 TRACE("(%p %p %p %u) function %04x\n", hdc
, ht
, mr
, handles
, mr
->rdFunction
);
545 switch (mr
->rdFunction
)
550 case META_DELETEOBJECT
:
551 DeleteObject(*(ht
->objectHandle
+ mr
->rdParm
[0]));
552 *(ht
->objectHandle
+ mr
->rdParm
[0]) = 0;
555 case META_SETBKCOLOR
:
556 SetBkColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
560 SetBkMode(hdc
, mr
->rdParm
[0]);
563 case META_SETMAPMODE
:
564 SetMapMode(hdc
, mr
->rdParm
[0]);
568 SetROP2(hdc
, mr
->rdParm
[0]);
572 SetRelAbs(hdc
, mr
->rdParm
[0]);
575 case META_SETPOLYFILLMODE
:
576 SetPolyFillMode(hdc
, mr
->rdParm
[0]);
579 case META_SETSTRETCHBLTMODE
:
580 SetStretchBltMode(hdc
, mr
->rdParm
[0]);
583 case META_SETTEXTCOLOR
:
584 SetTextColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
587 case META_SETWINDOWORG
:
588 SetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
591 case META_SETWINDOWEXT
:
592 SetWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
595 case META_SETVIEWPORTORG
:
596 SetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
599 case META_SETVIEWPORTEXT
:
600 SetViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
603 case META_OFFSETWINDOWORG
:
604 OffsetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
607 case META_SCALEWINDOWEXT
:
608 ScaleWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
609 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
612 case META_OFFSETVIEWPORTORG
:
613 OffsetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
616 case META_SCALEVIEWPORTEXT
:
617 ScaleViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
618 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
622 LineTo(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
626 MoveToEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
629 case META_EXCLUDECLIPRECT
:
630 ExcludeClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
631 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
634 case META_INTERSECTCLIPRECT
:
635 IntersectClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
636 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
640 Arc(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
641 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
642 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
643 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
647 Ellipse(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
648 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
652 FloodFill(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
653 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
657 Pie(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
658 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
659 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
660 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
664 Rectangle(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
665 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
669 RoundRect(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
670 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
671 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
675 PatBlt(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
676 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
677 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
685 SetPixel(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
686 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
689 case META_OFFSETCLIPRGN
:
690 OffsetClipRgn( hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
695 TextOutA(hdc
, (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 2],
696 (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 1],
697 (char *)(mr
->rdParm
+ 1), s1
);
701 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
703 Polygon(hdc
, pt
, mr
->rdParm
[0]);
704 HeapFree( GetProcessHeap(), 0, pt
);
708 case META_POLYPOLYGON
:
711 SHORT
*counts
= (SHORT
*)(mr
->rdParm
+ 1);
713 for (i
= total
= 0; i
< mr
->rdParm
[0]; i
++) total
+= counts
[i
];
714 pt
= convert_points( total
, (POINTS
*)(counts
+ mr
->rdParm
[0]) );
717 INT
*cnt32
= HeapAlloc( GetProcessHeap(), 0, mr
->rdParm
[0] * sizeof(*cnt32
) );
720 for (i
= 0; i
< mr
->rdParm
[0]; i
++) cnt32
[i
] = counts
[i
];
721 PolyPolygon( hdc
, pt
, cnt32
, mr
->rdParm
[0]);
722 HeapFree( GetProcessHeap(), 0, cnt32
);
725 HeapFree( GetProcessHeap(), 0, pt
);
730 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
732 Polyline( hdc
, pt
, mr
->rdParm
[0] );
733 HeapFree( GetProcessHeap(), 0, pt
);
738 RestoreDC(hdc
, (SHORT
)mr
->rdParm
[0]);
741 case META_SELECTOBJECT
:
742 SelectObject(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
746 Chord(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
747 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
748 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
749 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
752 case META_CREATEPATTERNBRUSH
:
753 switch (mr
->rdParm
[0])
756 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
757 MF_AddHandle(ht
, handles
,
758 CreatePatternBrush(CreateBitmap(infohdr
->biWidth
,
763 (sizeof(BITMAPINFOHEADER
) / 2) + 4)));
767 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
768 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( infohdr
, mr
->rdParm
[1] ));
772 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
778 case META_CREATEPENINDIRECT
:
781 pen
.lopnStyle
= mr
->rdParm
[0];
782 pen
.lopnWidth
.x
= (SHORT
)mr
->rdParm
[1];
783 pen
.lopnWidth
.y
= (SHORT
)mr
->rdParm
[2];
784 pen
.lopnColor
= MAKELONG( mr
->rdParm
[3], mr
->rdParm
[4] );
785 MF_AddHandle(ht
, handles
, CreatePenIndirect( &pen
));
789 case META_CREATEFONTINDIRECT
:
792 font
.lfHeight
= (SHORT
)mr
->rdParm
[0];
793 font
.lfWidth
= (SHORT
)mr
->rdParm
[1];
794 font
.lfEscapement
= (SHORT
)mr
->rdParm
[2];
795 font
.lfOrientation
= (SHORT
)mr
->rdParm
[3];
796 font
.lfWeight
= (SHORT
)mr
->rdParm
[4];
797 font
.lfItalic
= LOBYTE(mr
->rdParm
[5]);
798 font
.lfUnderline
= HIBYTE(mr
->rdParm
[5]);
799 font
.lfStrikeOut
= LOBYTE(mr
->rdParm
[6]);
800 font
.lfCharSet
= HIBYTE(mr
->rdParm
[6]);
801 font
.lfOutPrecision
= LOBYTE(mr
->rdParm
[7]);
802 font
.lfClipPrecision
= HIBYTE(mr
->rdParm
[7]);
803 font
.lfQuality
= LOBYTE(mr
->rdParm
[8]);
804 font
.lfPitchAndFamily
= HIBYTE(mr
->rdParm
[8]);
805 memcpy( font
.lfFaceName
, mr
->rdParm
+ 9, LF_FACESIZE
);
806 MF_AddHandle(ht
, handles
, CreateFontIndirectA( &font
));
810 case META_CREATEBRUSHINDIRECT
:
813 brush
.lbStyle
= mr
->rdParm
[0];
814 brush
.lbColor
= MAKELONG( mr
->rdParm
[1], mr
->rdParm
[2] );
815 brush
.lbHatch
= mr
->rdParm
[3];
816 MF_AddHandle(ht
, handles
, CreateBrushIndirect( &brush
));
820 case META_CREATEPALETTE
:
821 MF_AddHandle(ht
, handles
, CreatePalette((LPLOGPALETTE
)mr
->rdParm
));
824 case META_SETTEXTALIGN
:
825 SetTextAlign(hdc
, mr
->rdParm
[0]);
828 case META_SELECTPALETTE
:
829 GDISelectPalette(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]), mr
->rdParm
[0]);
832 case META_SETMAPPERFLAGS
:
833 SetMapperFlags(hdc
, MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
836 case META_REALIZEPALETTE
:
837 GDIRealizePalette(hdc
);
841 switch (mr
->rdParm
[0]) {
842 case GETSCALINGFACTOR
: /* get function ... would just NULL dereference */
843 case GETPHYSPAGESIZE
:
844 case GETPRINTINGOFFSET
:
847 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
850 Escape(hdc
, mr
->rdParm
[0], mr
->rdParm
[1], (LPCSTR
)&mr
->rdParm
[2], NULL
);
853 case META_EXTTEXTOUT
:
854 MF_Play_MetaExtTextOut( hdc
, mr
);
857 case META_STRETCHDIB
:
859 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[11]);
860 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, mr
->rdParm
[2] );
861 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[10], (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
862 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
863 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], bits
, info
,
864 mr
->rdParm
[2],MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
868 case META_DIBSTRETCHBLT
:
870 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[10]);
871 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, DIB_RGB_COLORS
);
872 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
873 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
874 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2], bits
, info
,
875 DIB_RGB_COLORS
,MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
879 case META_STRETCHBLT
:
881 HDC hdcSrc
= CreateCompatibleDC(hdc
);
882 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[10], /*Width */
883 mr
->rdParm
[11], /*Height*/
884 mr
->rdParm
[13], /*Planes*/
885 mr
->rdParm
[14], /*BitsPixel*/
886 &mr
->rdParm
[15]); /*bits*/
887 SelectObject(hdcSrc
,hbitmap
);
888 StretchBlt(hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
889 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
890 hdcSrc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
891 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
892 MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
899 HDC hdcSrc
= CreateCompatibleDC(hdc
);
900 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[7]/*Width */,
901 mr
->rdParm
[8]/*Height*/,
902 mr
->rdParm
[10]/*Planes*/,
903 mr
->rdParm
[11]/*BitsPixel*/,
904 &mr
->rdParm
[12]/*bits*/);
905 SelectObject(hdcSrc
,hbitmap
);
906 BitBlt(hdc
,(SHORT
)mr
->rdParm
[6],(SHORT
)mr
->rdParm
[5],
907 (SHORT
)mr
->rdParm
[4],(SHORT
)mr
->rdParm
[3],
908 hdcSrc
, (SHORT
)mr
->rdParm
[2],(SHORT
)mr
->rdParm
[1],
909 MAKELONG(0,mr
->rdParm
[0]));
914 case META_CREATEREGION
:
916 HRGN hrgn
= CreateRectRgn(0,0,0,0);
918 MF_Play_MetaCreateRegion(mr
, hrgn
);
919 MF_AddHandle(ht
, handles
, hrgn
);
923 case META_FILLREGION
:
924 FillRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]),
925 *(ht
->objectHandle
+ mr
->rdParm
[0]));
928 case META_FRAMEREGION
:
929 FrameRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[3]),
930 *(ht
->objectHandle
+ mr
->rdParm
[2]),
931 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
934 case META_INVERTREGION
:
935 InvertRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
938 case META_PAINTREGION
:
939 PaintRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
942 case META_SELECTCLIPREGION
:
946 if (mr
->rdParm
[0]) hrgn
= *(ht
->objectHandle
+ mr
->rdParm
[0]);
947 SelectClipRgn(hdc
, hrgn
);
951 case META_DIBCREATEPATTERNBRUSH
:
952 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
953 but there's no difference */
954 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( mr
->rdParm
+ 2, mr
->rdParm
[1] ));
958 /* In practice I've found that there are two layouts for
959 META_DIBBITBLT, one (the first here) is the usual one when a src
960 dc is actually passed to it, the second occurs when the src dc is
961 passed in as NULL to the creating BitBlt. As the second case has
962 no dib, a size check will suffice to distinguish.
964 Caolan.McNamara@ul.ie */
966 if (mr
->rdSize
> 12) {
967 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[8]);
968 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size(info
, mr
->rdParm
[0]);
970 StretchDIBits(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
971 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
972 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4], bits
, info
,
973 DIB_RGB_COLORS
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
975 else /* equivalent to a PatBlt */
976 PatBlt(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
977 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
978 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
981 case META_SETTEXTCHAREXTRA
:
982 SetTextCharacterExtra(hdc
, (SHORT
)mr
->rdParm
[0]);
985 case META_SETTEXTJUSTIFICATION
:
986 SetTextJustification(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
989 case META_EXTFLOODFILL
:
990 ExtFloodFill(hdc
, (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
991 MAKELONG(mr
->rdParm
[1], mr
->rdParm
[2]),
995 case META_SETDIBTODEV
:
997 BITMAPINFO
*info
= (BITMAPINFO
*) &(mr
->rdParm
[9]);
998 char *bits
= (char *)info
+ bitmap_info_size( info
, mr
->rdParm
[0] );
999 SetDIBitsToDevice(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
1000 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
1001 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
1002 mr
->rdParm
[2], mr
->rdParm
[1], bits
, info
,
1007 #define META_UNIMP(x) case x: \
1008 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1010 META_UNIMP(META_DRAWTEXT
)
1011 META_UNIMP(META_ANIMATEPALETTE
)
1012 META_UNIMP(META_SETPALENTRIES
)
1013 META_UNIMP(META_RESIZEPALETTE
)
1014 META_UNIMP(META_RESETDC
)
1015 META_UNIMP(META_STARTDOC
)
1016 META_UNIMP(META_STARTPAGE
)
1017 META_UNIMP(META_ENDPAGE
)
1018 META_UNIMP(META_ABORTDOC
)
1019 META_UNIMP(META_ENDDOC
)
1020 META_UNIMP(META_CREATEBRUSH
)
1021 META_UNIMP(META_CREATEBITMAPINDIRECT
)
1022 META_UNIMP(META_CREATEBITMAP
)
1026 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr
->rdFunction
);
1032 /******************************************************************
1033 * SetMetaFileBitsEx (GDI32.@)
1035 * Create a metafile from raw data. No checking of the data is performed.
1036 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1039 * size [I] size of metafile, in bytes
1040 * lpData [I] pointer to metafile data
1043 * Success: Handle to metafile.
1046 HMETAFILE WINAPI
SetMetaFileBitsEx( UINT size
, const BYTE
*lpData
)
1048 const METAHEADER
*mh_in
= (const METAHEADER
*)lpData
;
1051 if (size
& 1) return 0;
1053 if (!size
|| mh_in
->mtType
!= METAFILE_MEMORY
|| mh_in
->mtVersion
!= MFVERSION
||
1054 mh_in
->mtHeaderSize
!= sizeof(METAHEADER
) / 2)
1056 SetLastError(ERROR_INVALID_DATA
);
1060 mh_out
= HeapAlloc( GetProcessHeap(), 0, size
);
1063 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1067 memcpy(mh_out
, mh_in
, size
);
1068 mh_out
->mtSize
= size
/ 2;
1069 return MF_Create_HMETAFILE(mh_out
);
1072 /*****************************************************************
1073 * GetMetaFileBitsEx (GDI32.@)
1075 * Get raw metafile data.
1077 * Copies the data from metafile _hmf_ into the buffer _buf_.
1081 * nSize [I] size of buf
1082 * buf [O] buffer to receive raw metafile data
1085 * If _buf_ is zero, returns size of buffer required. Otherwise,
1086 * returns number of bytes copied.
1088 UINT WINAPI
GetMetaFileBitsEx( HMETAFILE hmf
, UINT nSize
, LPVOID buf
)
1090 METAHEADER
*mh
= GDI_GetObjPtr( hmf
, OBJ_METAFILE
);
1092 BOOL mf_copy
= FALSE
;
1094 TRACE("(%p,%d,%p)\n", hmf
, nSize
, buf
);
1095 if (!mh
) return 0; /* FIXME: error code */
1096 if(mh
->mtType
== METAFILE_DISK
)
1098 mh
= MF_LoadDiskBasedMetaFile( mh
);
1101 GDI_ReleaseObj( hmf
);
1106 mfSize
= mh
->mtSize
* 2;
1109 if(mfSize
> nSize
) mfSize
= nSize
;
1110 memmove(buf
, mh
, mfSize
);
1112 if (mf_copy
) HeapFree( GetProcessHeap(), 0, mh
);
1113 GDI_ReleaseObj( hmf
);
1114 TRACE("returning size %d\n", mfSize
);
1118 #include <pshpack2.h>
1121 DWORD magic
; /* WMFC */
1127 DWORD unk0e
; /* 0 */
1130 DWORD remaining_size
;
1134 #include <poppack.h>
1136 static const DWORD wmfc_magic
= 0x43464d57;
1138 /******************************************************************
1141 * Helper for GetWinMetaFileBits
1143 * Add the MFCOMMENT record[s] which is essentially a copy
1144 * of the original emf.
1146 static BOOL
add_mf_comment(HDC hdc
, HENHMETAFILE emf
)
1148 DWORD size
= GetEnhMetaFileBits(emf
, 0, NULL
), i
;
1149 BYTE
*bits
, *chunk_data
;
1150 mf_comment_chunk
*chunk
= NULL
;
1152 static const DWORD max_chunk_size
= 0x2000;
1154 if(!size
) return FALSE
;
1155 chunk_data
= bits
= HeapAlloc(GetProcessHeap(), 0, size
);
1156 if(!bits
) return FALSE
;
1157 if(!GetEnhMetaFileBits(emf
, size
, bits
)) goto end
;
1159 chunk
= HeapAlloc(GetProcessHeap(), 0, max_chunk_size
+ FIELD_OFFSET(mf_comment_chunk
, emf_data
));
1160 if(!chunk
) goto end
;
1162 chunk
->magic
= wmfc_magic
;
1167 chunk
->checksum
= 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1169 chunk
->num_chunks
= (size
+ max_chunk_size
- 1) / max_chunk_size
;
1170 chunk
->chunk_size
= max_chunk_size
;
1171 chunk
->remaining_size
= size
;
1172 chunk
->emf_size
= size
;
1174 for(i
= 0; i
< chunk
->num_chunks
; i
++)
1176 if(i
== chunk
->num_chunks
- 1) /* last chunk */
1177 chunk
->chunk_size
= chunk
->remaining_size
;
1179 chunk
->remaining_size
-= chunk
->chunk_size
;
1180 memcpy(&chunk
->emf_data
, chunk_data
, chunk
->chunk_size
);
1181 chunk_data
+= chunk
->chunk_size
;
1183 if(!Escape(hdc
, MFCOMMENT
, chunk
->chunk_size
+ FIELD_OFFSET(mf_comment_chunk
, emf_data
), (char*)chunk
, NULL
))
1188 HeapFree(GetProcessHeap(), 0, chunk
);
1189 HeapFree(GetProcessHeap(), 0, bits
);
1193 /*******************************************************************
1196 * Behaves somewhat differently to MulDiv when the answer is -ve
1197 * and also rounds n.5 towards zero
1199 static INT
muldiv(INT m1
, INT m2
, INT d
)
1203 ret
= ((LONGLONG
)m1
* m2
+ d
/2) / d
; /* Always add d/2 even if ret will be -ve */
1205 if((LONGLONG
)m1
* m2
* 2 == (2 * ret
- 1) * d
) /* If the answer is exactly n.5 round towards zero */
1213 /******************************************************************
1216 * Helper for GetWinMetaFileBits
1218 * Add the SetWindowOrg and SetWindowExt records
1220 static BOOL
set_window(HDC hdc
, HENHMETAFILE emf
, HDC ref_dc
, INT map_mode
)
1222 ENHMETAHEADER header
;
1223 INT horz_res
, vert_res
, horz_size
, vert_size
;
1226 if(!GetEnhMetaFileHeader(emf
, sizeof(header
), &header
)) return FALSE
;
1228 horz_res
= GetDeviceCaps(ref_dc
, HORZRES
);
1229 vert_res
= GetDeviceCaps(ref_dc
, VERTRES
);
1230 horz_size
= GetDeviceCaps(ref_dc
, HORZSIZE
);
1231 vert_size
= GetDeviceCaps(ref_dc
, VERTSIZE
);
1237 case MM_ANISOTROPIC
:
1238 pt
.y
= muldiv(header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1239 pt
.x
= muldiv(header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1242 pt
.y
= muldiv(-header
.rclFrame
.top
, 1, 10) + 1;
1243 pt
.x
= muldiv( header
.rclFrame
.left
, 1, 10);
1246 pt
.y
= -header
.rclFrame
.top
+ 1;
1247 pt
.x
= (header
.rclFrame
.left
>= 0) ? header
.rclFrame
.left
: header
.rclFrame
.left
+ 1; /* See the tests */
1250 pt
.y
= muldiv(-header
.rclFrame
.top
, 10, 254) + 1;
1251 pt
.x
= muldiv( header
.rclFrame
.left
, 10, 254);
1254 pt
.y
= muldiv(-header
.rclFrame
.top
, 100, 254) + 1;
1255 pt
.x
= muldiv( header
.rclFrame
.left
, 100, 254);
1258 pt
.y
= muldiv(-header
.rclFrame
.top
, 72 * 20, 2540) + 1;
1259 pt
.x
= muldiv( header
.rclFrame
.left
, 72 * 20, 2540);
1262 WARN("Unknown map mode %d\n", map_mode
);
1265 SetWindowOrgEx(hdc
, pt
.x
, pt
.y
, NULL
);
1267 pt
.x
= muldiv(header
.rclFrame
.right
- header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1268 pt
.y
= muldiv(header
.rclFrame
.bottom
- header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1269 SetWindowExtEx(hdc
, pt
.x
, pt
.y
, NULL
);
1273 /******************************************************************
1274 * GetWinMetaFileBits [GDI32.@]
1276 UINT WINAPI
GetWinMetaFileBits(HENHMETAFILE hemf
,
1277 UINT cbBuffer
, LPBYTE lpbBuffer
,
1278 INT map_mode
, HDC hdcRef
)
1282 UINT ret
, full_size
;
1285 GetClipBox(hdcRef
, &rc
);
1287 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf
, cbBuffer
, lpbBuffer
,
1288 map_mode
, hdcRef
, wine_dbgstr_rect(&rc
));
1290 hdcmf
= CreateMetaFileW(NULL
);
1292 add_mf_comment(hdcmf
, hemf
);
1293 SetMapMode(hdcmf
, map_mode
);
1294 if(!set_window(hdcmf
, hemf
, hdcRef
, map_mode
))
1297 PlayEnhMetaFile(hdcmf
, hemf
, &rc
);
1298 hmf
= CloseMetaFile(hdcmf
);
1299 full_size
= GetMetaFileBitsEx(hmf
, 0, NULL
);
1300 ret
= GetMetaFileBitsEx(hmf
, cbBuffer
, lpbBuffer
);
1301 DeleteMetaFile(hmf
);
1303 if(ret
&& ret
== full_size
&& lpbBuffer
) /* fixup checksum, but only if retrieving all of the bits */
1306 METARECORD
*comment_rec
= (METARECORD
*)(lpbBuffer
+ sizeof(METAHEADER
));
1309 for(i
= 0; i
< full_size
/ 2; i
++)
1310 checksum
+= ((WORD
*)lpbBuffer
)[i
];
1311 comment_rec
->rdParm
[8] = ~checksum
+ 1;
1316 DeleteMetaFile(CloseMetaFile(hdcmf
));
1320 /******************************************************************
1321 * MF_Play_MetaCreateRegion
1323 * Handles META_CREATEREGION for PlayMetaFileRecord().
1325 * The layout of the record looks something like this:
1330 * 2 Looks like a handle? - not constant
1332 * 4 Total number of bytes
1333 * 5 No. of separate bands = n [see below]
1334 * 6 Largest number of x co-ords in a band
1335 * 7-10 Bounding box x1 y1 x2 y2
1338 * Regions are divided into bands that are uniform in the
1339 * y-direction. Each band consists of pairs of on/off x-coords and is
1341 * m y0 y1 x1 x2 x3 ... xm m
1342 * into successive rdParm[]s.
1344 * This is probably just a dump of the internal RGNOBJ?
1350 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
)
1355 HRGN hrgn2
= CreateRectRgn( 0, 0, 0, 0 );
1357 for(band
= 0, start
= &(mr
->rdParm
[11]); band
< mr
->rdParm
[5];
1358 band
++, start
= end
+ 1) {
1359 if(*start
/ 2 != (*start
+ 1) / 2) {
1360 WARN("Delimiter not even.\n");
1361 DeleteObject( hrgn2
);
1365 end
= start
+ *start
+ 3;
1366 if(end
> (WORD
*)mr
+ mr
->rdSize
) {
1367 WARN("End points outside record.\n");
1368 DeleteObject( hrgn2
);
1372 if(*start
!= *end
) {
1373 WARN("Mismatched delimiters.\n");
1374 DeleteObject( hrgn2
);
1378 y0
= *(INT16
*)(start
+ 1);
1379 y1
= *(INT16
*)(start
+ 2);
1380 for(pair
= 0; pair
< *start
/ 2; pair
++) {
1381 SetRectRgn( hrgn2
, *(INT16
*)(start
+ 3 + 2*pair
), y0
,
1382 *(INT16
*)(start
+ 4 + 2*pair
), y1
);
1383 CombineRgn(hrgn
, hrgn
, hrgn2
, RGN_OR
);
1386 DeleteObject( hrgn2
);
1391 /******************************************************************
1392 * MF_Play_MetaExtTextOut
1394 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1397 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
)
1406 BOOL isrect
= mr
->rdParm
[3] & (ETO_OPAQUE
| ETO_CLIPPED
);
1408 s1
= mr
->rdParm
[2]; /* String length */
1409 len
= sizeof(METARECORD
) + (((s1
+ 1) >> 1) * 2) + 2 * sizeof(short)
1410 + sizeof(UINT16
) + (isrect
? 4 * sizeof(SHORT
) : 0);
1411 /* rec len without dx array */
1413 sot
= (LPSTR
)&mr
->rdParm
[4]; /* start_of_text */
1416 rect
.left
= (SHORT
)mr
->rdParm
[4];
1417 rect
.top
= (SHORT
)mr
->rdParm
[5];
1418 rect
.right
= (SHORT
)mr
->rdParm
[6];
1419 rect
.bottom
= (SHORT
)mr
->rdParm
[7];
1420 sot
+= 4 * sizeof(SHORT
); /* there is a rectangle, so add offset */
1423 if (mr
->rdSize
== len
/ 2)
1424 dxx
= NULL
; /* determine if array is present */
1426 if (mr
->rdSize
== (len
+ s1
* sizeof(INT16
)) / 2)
1428 dxx
= (SHORT
*)(sot
+(((s1
+1)>>1)*2));
1429 dx
= HeapAlloc( GetProcessHeap(), 0, s1
*sizeof(INT
));
1430 if (dx
) for (i
= 0; i
< s1
; i
++) dx
[i
] = dxx
[i
];
1433 TRACE("%s len: %d\n", sot
, mr
->rdSize
);
1434 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1435 len
, s1
, mr
->rdSize
, mr
->rdParm
[3]);
1436 dxx
= NULL
; /* shouldn't happen -- but if, we continue with NULL */
1439 (SHORT
)mr
->rdParm
[1], /* X position */
1440 (SHORT
)mr
->rdParm
[0], /* Y position */
1441 mr
->rdParm
[3], /* options */
1442 &rect
, /* rectangle */
1444 s1
, dx
); /* length, dx array */
1447 TRACE("%s len: %d dx0: %d\n", sot
, mr
->rdSize
, dx
[0]);
1448 HeapFree( GetProcessHeap(), 0, dx
);