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"
59 #include "wine/debug.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(metafile
);
73 /******************************************************************
76 * Add a handle to an external handle table and return the index
78 static int MF_AddHandle(HANDLETABLE
*ht
, UINT htlen
, HGDIOBJ hobj
)
82 for (i
= 0; i
< htlen
; i
++)
84 if (*(ht
->objectHandle
+ i
) == 0)
86 *(ht
->objectHandle
+ i
) = hobj
;
94 /******************************************************************
95 * MF_Create_HMETATFILE
97 * Creates a (32 bit) HMETAFILE object from a METAHEADER
99 * HMETAFILEs are GDI objects.
101 HMETAFILE
MF_Create_HMETAFILE(METAHEADER
*mh
)
103 return alloc_gdi_handle( mh
, OBJ_METAFILE
, NULL
);
106 /******************************************************************
109 * Convert an array of POINTS to an array of POINT.
110 * Result must be freed by caller.
112 static POINT
*convert_points( UINT count
, const POINTS
*pts
)
115 POINT
*ret
= HeapAlloc( GetProcessHeap(), 0, count
* sizeof(*ret
) );
118 for (i
= 0; i
< count
; i
++)
127 /******************************************************************
128 * DeleteMetaFile (GDI32.@)
130 * Delete a memory-based metafile.
133 BOOL WINAPI
DeleteMetaFile( HMETAFILE hmf
)
135 METAHEADER
*mh
= free_gdi_handle( hmf
);
137 if (!mh
) return FALSE
;
138 HeapFree( GetProcessHeap(), 0, mh
);
142 /******************************************************************
145 * Returns a pointer to a memory based METAHEADER read in from file HFILE
148 static METAHEADER
*MF_ReadMetaFile(HANDLE hfile
)
151 DWORD BytesRead
, size
;
153 size
= sizeof(METAHEADER
);
154 mh
= HeapAlloc( GetProcessHeap(), 0, size
);
156 if(ReadFile( hfile
, mh
, size
, &BytesRead
, NULL
) == 0 ||
158 HeapFree( GetProcessHeap(), 0, mh
);
161 if (mh
->mtType
!= METAFILE_MEMORY
|| mh
->mtVersion
!= MFVERSION
||
162 mh
->mtHeaderSize
!= size
/ 2)
164 HeapFree( GetProcessHeap(), 0, mh
);
167 size
= mh
->mtSize
* 2;
168 mh
= HeapReAlloc( GetProcessHeap(), 0, mh
, size
);
170 size
-= sizeof(METAHEADER
);
171 if(ReadFile( hfile
, (char *)mh
+ sizeof(METAHEADER
), size
, &BytesRead
,
174 HeapFree( GetProcessHeap(), 0, mh
);
178 if (mh
->mtType
!= METAFILE_MEMORY
) {
179 WARN("Disk metafile had mtType = %04x\n", mh
->mtType
);
180 mh
->mtType
= METAFILE_MEMORY
;
185 /******************************************************************
186 * GetMetaFileA (GDI32.@)
188 * Read a metafile from a file. Returns handle to a memory-based metafile.
190 HMETAFILE WINAPI
GetMetaFileA( LPCSTR lpFilename
)
195 TRACE("%s\n", lpFilename
);
200 if((hFile
= CreateFileA(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
201 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
204 mh
= MF_ReadMetaFile(hFile
);
207 return MF_Create_HMETAFILE( mh
);
210 /******************************************************************
211 * GetMetaFileW (GDI32.@)
213 HMETAFILE WINAPI
GetMetaFileW( LPCWSTR lpFilename
)
218 TRACE("%s\n", debugstr_w(lpFilename
));
223 if((hFile
= CreateFileW(lpFilename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
224 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
)
227 mh
= MF_ReadMetaFile(hFile
);
230 return MF_Create_HMETAFILE( mh
);
234 /******************************************************************
235 * MF_LoadDiskBasedMetaFile
237 * Creates a new memory-based metafile from a disk-based one.
239 static METAHEADER
*MF_LoadDiskBasedMetaFile(METAHEADER
*mh
)
245 if(mh
->mtType
!= METAFILE_DISK
) {
246 ERR("Not a disk based metafile\n");
249 mhd
= (METAHEADERDISK
*)((char *)mh
+ sizeof(METAHEADER
));
251 if((hfile
= CreateFileA(mhd
->filename
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
252 OPEN_EXISTING
, 0, 0)) == INVALID_HANDLE_VALUE
) {
253 WARN("Can't open file of disk based metafile\n");
256 mh2
= MF_ReadMetaFile(hfile
);
261 /******************************************************************
262 * MF_CreateMetaHeaderDisk
264 * Take a memory based METAHEADER and change it to a disk based METAHEADER
265 * associated with filename. Note: Trashes contents of old one.
267 METAHEADER
*MF_CreateMetaHeaderDisk(METAHEADER
*mh
, LPCVOID filename
, BOOL uni
)
271 mh
= HeapReAlloc( GetProcessHeap(), 0, mh
,
272 sizeof(METAHEADER
) + sizeof(METAHEADERDISK
));
273 mh
->mtType
= METAFILE_DISK
;
274 mhd
= (METAHEADERDISK
*)((char *)mh
+ sizeof(METAHEADER
));
277 WideCharToMultiByte(CP_ACP
, 0, filename
, -1,
278 mhd
->filename
, sizeof mhd
->filename
, NULL
, NULL
);
280 lstrcpynA( mhd
->filename
, filename
, sizeof mhd
->filename
);
284 /* return a copy of the metafile bits, to be freed with HeapFree */
285 static METAHEADER
*get_metafile_bits( HMETAFILE hmf
)
287 METAHEADER
*ret
, *mh
= GDI_GetObjPtr( hmf
, OBJ_METAFILE
);
289 if (!mh
) return NULL
;
291 if (mh
->mtType
!= METAFILE_DISK
)
293 ret
= HeapAlloc( GetProcessHeap(), 0, mh
->mtSize
* 2 );
294 if (ret
) memcpy( ret
, mh
, mh
->mtSize
* 2 );
296 else ret
= MF_LoadDiskBasedMetaFile( mh
);
298 GDI_ReleaseObj( hmf
);
302 /******************************************************************
303 * CopyMetaFileW (GDI32.@)
305 * Copies the metafile corresponding to hSrcMetaFile to either
306 * a disk file, if a filename is given, or to a new memory based
307 * metafile, if lpFileName is NULL.
310 * hSrcMetaFile [I] handle of metafile to copy
311 * lpFilename [I] filename if copying to a file
314 * Handle to metafile copy on success, NULL on failure.
317 * Copying to disk returns NULL even if successful.
319 HMETAFILE WINAPI
CopyMetaFileW( HMETAFILE hSrcMetaFile
, LPCWSTR lpFilename
)
321 METAHEADER
*mh
= get_metafile_bits( hSrcMetaFile
);
324 TRACE("(%p,%s)\n", hSrcMetaFile
, debugstr_w(lpFilename
));
328 if(lpFilename
) { /* disk based metafile */
330 if((hFile
= CreateFileW(lpFilename
, GENERIC_WRITE
, 0, NULL
,
331 CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
) {
332 HeapFree( GetProcessHeap(), 0, mh
);
335 WriteFile(hFile
, mh
, mh
->mtSize
* 2, &w
, NULL
);
339 return MF_Create_HMETAFILE( mh
);
343 /******************************************************************
344 * CopyMetaFileA (GDI32.@)
348 HMETAFILE WINAPI
CopyMetaFileA( HMETAFILE hSrcMetaFile
, LPCSTR lpFilename
)
350 UNICODE_STRING lpFilenameW
;
353 if (lpFilename
) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW
, lpFilename
);
354 else lpFilenameW
.Buffer
= NULL
;
356 ret
= CopyMetaFileW( hSrcMetaFile
, lpFilenameW
.Buffer
);
357 if (lpFilenameW
.Buffer
)
358 RtlFreeUnicodeString(&lpFilenameW
);
362 /******************************************************************
363 * PlayMetaFile (GDI32.@)
365 * Renders the metafile specified by hmf in the DC specified by
366 * hdc. Returns FALSE on failure, TRUE on success.
369 * hdc [I] handle of DC to render in
370 * hmf [I] handle of metafile to render
376 BOOL WINAPI
PlayMetaFile( HDC hdc
, HMETAFILE hmf
)
378 METAHEADER
*mh
= get_metafile_bits( hmf
);
381 unsigned int offset
= 0;
388 if (!mh
) return FALSE
;
391 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
392 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
393 hPal
= GetCurrentObject(hdc
, OBJ_PAL
);
395 hRgn
= CreateRectRgn(0, 0, 0, 0);
396 if (!GetClipRgn(hdc
, hRgn
))
402 /* create the handle table */
403 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
404 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
407 HeapFree( GetProcessHeap(), 0, mh
);
411 /* loop through metafile playing records */
412 offset
= mh
->mtHeaderSize
* 2;
413 while (offset
< mh
->mtSize
* 2)
415 mr
= (METARECORD
*)((char *)mh
+ offset
);
416 TRACE("offset=%04x,size=%08x\n",
418 if (mr
->rdSize
< 3) { /* catch illegal record sizes */
419 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
420 mr
->rdSize
,offset
,mh
->mtSize
*2);
424 offset
+= mr
->rdSize
* 2;
425 if (mr
->rdFunction
== META_EOF
) {
426 TRACE("Got META_EOF so stopping\n");
429 PlayMetaFileRecord( hdc
, ht
, mr
, mh
->mtNoObjects
);
433 SelectObject(hdc
, hPen
);
434 SelectObject(hdc
, hBrush
);
435 SelectPalette(hdc
, hPal
, FALSE
);
436 ExtSelectClipRgn(hdc
, hRgn
, RGN_COPY
);
439 /* free objects in handle table */
440 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
441 if(*(ht
->objectHandle
+ i
) != 0)
442 DeleteObject(*(ht
->objectHandle
+ i
));
444 HeapFree( GetProcessHeap(), 0, ht
);
445 HeapFree( GetProcessHeap(), 0, mh
);
449 /******************************************************************
450 * EnumMetaFile (GDI32.@)
452 * Loop through the metafile records in hmf, calling the user-specified
453 * function for each one, stopping when the user's function returns FALSE
454 * (which is considered to be failure)
455 * or when no records are left (which is considered to be success).
458 * TRUE on success, FALSE on failure.
460 BOOL WINAPI
EnumMetaFile(HDC hdc
, HMETAFILE hmf
, MFENUMPROC lpEnumFunc
, LPARAM lpData
)
462 METAHEADER
*mh
= get_metafile_bits( hmf
);
467 unsigned int offset
= 0;
472 TRACE("(%p,%p,%p,%lx)\n", hdc
, hmf
, lpEnumFunc
, lpData
);
474 if (!mh
) return FALSE
;
476 /* save the current pen, brush and font */
477 hPen
= GetCurrentObject(hdc
, OBJ_PEN
);
478 hBrush
= GetCurrentObject(hdc
, OBJ_BRUSH
);
479 hFont
= GetCurrentObject(hdc
, OBJ_FONT
);
481 ht
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
482 sizeof(HANDLETABLE
) * mh
->mtNoObjects
);
484 /* loop through metafile records */
485 offset
= mh
->mtHeaderSize
* 2;
487 while (offset
< (mh
->mtSize
* 2))
489 mr
= (METARECORD
*)((char *)mh
+ offset
);
490 if(mr
->rdFunction
== META_EOF
) {
491 TRACE("Got META_EOF so stopping\n");
494 TRACE("Calling EnumFunc with record type %x\n",
496 if (!lpEnumFunc( hdc
, ht
, mr
, mh
->mtNoObjects
, lpData
))
502 offset
+= (mr
->rdSize
* 2);
505 /* restore pen, brush and font */
506 SelectObject(hdc
, hBrush
);
507 SelectObject(hdc
, hPen
);
508 SelectObject(hdc
, hFont
);
510 /* free objects in handle table */
511 for(i
= 0; i
< mh
->mtNoObjects
; i
++)
512 if(*(ht
->objectHandle
+ i
) != 0)
513 DeleteObject(*(ht
->objectHandle
+ i
));
515 HeapFree( GetProcessHeap(), 0, ht
);
516 HeapFree( GetProcessHeap(), 0, mh
);
520 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
);
521 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
);
522 /******************************************************************
523 * PlayMetaFileRecord (GDI32.@)
525 * Render a single metafile record specified by *mr in the DC hdc, while
526 * using the handle table *ht, of length handles,
527 * to store metafile objects.
530 * The following metafile records are unimplemented:
532 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
533 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
534 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
536 BOOL WINAPI
PlayMetaFileRecord( HDC hdc
, HANDLETABLE
*ht
, METARECORD
*mr
, UINT handles
)
540 BITMAPINFOHEADER
*infohdr
;
542 TRACE("(%p %p %p %u) function %04x\n", hdc
, ht
, mr
, handles
, mr
->rdFunction
);
544 switch (mr
->rdFunction
)
549 case META_DELETEOBJECT
:
550 DeleteObject(*(ht
->objectHandle
+ mr
->rdParm
[0]));
551 *(ht
->objectHandle
+ mr
->rdParm
[0]) = 0;
554 case META_SETBKCOLOR
:
555 SetBkColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
559 SetBkMode(hdc
, mr
->rdParm
[0]);
562 case META_SETMAPMODE
:
563 SetMapMode(hdc
, mr
->rdParm
[0]);
567 SetROP2(hdc
, mr
->rdParm
[0]);
571 SetRelAbs(hdc
, mr
->rdParm
[0]);
574 case META_SETPOLYFILLMODE
:
575 SetPolyFillMode(hdc
, mr
->rdParm
[0]);
578 case META_SETSTRETCHBLTMODE
:
579 SetStretchBltMode(hdc
, mr
->rdParm
[0]);
582 case META_SETTEXTCOLOR
:
583 SetTextColor(hdc
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
586 case META_SETWINDOWORG
:
587 SetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
590 case META_SETWINDOWEXT
:
591 SetWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
594 case META_SETVIEWPORTORG
:
595 SetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
598 case META_SETVIEWPORTEXT
:
599 SetViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
602 case META_OFFSETWINDOWORG
:
603 OffsetWindowOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
606 case META_SCALEWINDOWEXT
:
607 ScaleWindowExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
608 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
611 case META_OFFSETVIEWPORTORG
:
612 OffsetViewportOrgEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
615 case META_SCALEVIEWPORTEXT
:
616 ScaleViewportExtEx(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
617 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
621 LineTo(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
625 MoveToEx(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0], NULL
);
628 case META_EXCLUDECLIPRECT
:
629 ExcludeClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
630 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
633 case META_INTERSECTCLIPRECT
:
634 IntersectClipRect( hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
635 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
639 Arc(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
640 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
641 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
642 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
646 Ellipse(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
647 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
651 FloodFill(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
652 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
656 Pie(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
657 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
658 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
659 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
663 Rectangle(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
664 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
668 RoundRect(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
669 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
670 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
674 PatBlt(hdc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
675 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
676 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
684 SetPixel(hdc
, (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
685 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
688 case META_OFFSETCLIPRGN
:
689 OffsetClipRgn( hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0] );
694 TextOutA(hdc
, (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 2],
695 (SHORT
)mr
->rdParm
[((s1
+ 1) >> 1) + 1],
696 (char *)(mr
->rdParm
+ 1), s1
);
700 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
702 Polygon(hdc
, pt
, mr
->rdParm
[0]);
703 HeapFree( GetProcessHeap(), 0, pt
);
707 case META_POLYPOLYGON
:
710 SHORT
*counts
= (SHORT
*)(mr
->rdParm
+ 1);
712 for (i
= total
= 0; i
< mr
->rdParm
[0]; i
++) total
+= counts
[i
];
713 pt
= convert_points( total
, (POINTS
*)(counts
+ mr
->rdParm
[0]) );
716 INT
*cnt32
= HeapAlloc( GetProcessHeap(), 0, mr
->rdParm
[0] * sizeof(*cnt32
) );
719 for (i
= 0; i
< mr
->rdParm
[0]; i
++) cnt32
[i
] = counts
[i
];
720 PolyPolygon( hdc
, pt
, cnt32
, mr
->rdParm
[0]);
721 HeapFree( GetProcessHeap(), 0, cnt32
);
724 HeapFree( GetProcessHeap(), 0, pt
);
729 if ((pt
= convert_points( mr
->rdParm
[0], (POINTS
*)(mr
->rdParm
+ 1))))
731 Polyline( hdc
, pt
, mr
->rdParm
[0] );
732 HeapFree( GetProcessHeap(), 0, pt
);
737 RestoreDC(hdc
, (SHORT
)mr
->rdParm
[0]);
740 case META_SELECTOBJECT
:
741 SelectObject(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
745 Chord(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
746 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
747 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
748 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
751 case META_CREATEPATTERNBRUSH
:
752 switch (mr
->rdParm
[0])
755 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
756 MF_AddHandle(ht
, handles
,
757 CreatePatternBrush(CreateBitmap(infohdr
->biWidth
,
762 (sizeof(BITMAPINFOHEADER
) / 2) + 4)));
766 infohdr
= (BITMAPINFOHEADER
*)(mr
->rdParm
+ 2);
767 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( infohdr
, mr
->rdParm
[1] ));
771 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
777 case META_CREATEPENINDIRECT
:
780 pen
.lopnStyle
= mr
->rdParm
[0];
781 pen
.lopnWidth
.x
= (SHORT
)mr
->rdParm
[1];
782 pen
.lopnWidth
.y
= (SHORT
)mr
->rdParm
[2];
783 pen
.lopnColor
= MAKELONG( mr
->rdParm
[3], mr
->rdParm
[4] );
784 MF_AddHandle(ht
, handles
, CreatePenIndirect( &pen
));
788 case META_CREATEFONTINDIRECT
:
791 font
.lfHeight
= (SHORT
)mr
->rdParm
[0];
792 font
.lfWidth
= (SHORT
)mr
->rdParm
[1];
793 font
.lfEscapement
= (SHORT
)mr
->rdParm
[2];
794 font
.lfOrientation
= (SHORT
)mr
->rdParm
[3];
795 font
.lfWeight
= (SHORT
)mr
->rdParm
[4];
796 font
.lfItalic
= LOBYTE(mr
->rdParm
[5]);
797 font
.lfUnderline
= HIBYTE(mr
->rdParm
[5]);
798 font
.lfStrikeOut
= LOBYTE(mr
->rdParm
[6]);
799 font
.lfCharSet
= HIBYTE(mr
->rdParm
[6]);
800 font
.lfOutPrecision
= LOBYTE(mr
->rdParm
[7]);
801 font
.lfClipPrecision
= HIBYTE(mr
->rdParm
[7]);
802 font
.lfQuality
= LOBYTE(mr
->rdParm
[8]);
803 font
.lfPitchAndFamily
= HIBYTE(mr
->rdParm
[8]);
804 memcpy( font
.lfFaceName
, mr
->rdParm
+ 9, LF_FACESIZE
);
805 MF_AddHandle(ht
, handles
, CreateFontIndirectA( &font
));
809 case META_CREATEBRUSHINDIRECT
:
812 brush
.lbStyle
= mr
->rdParm
[0];
813 brush
.lbColor
= MAKELONG( mr
->rdParm
[1], mr
->rdParm
[2] );
814 brush
.lbHatch
= mr
->rdParm
[3];
815 MF_AddHandle(ht
, handles
, CreateBrushIndirect( &brush
));
819 case META_CREATEPALETTE
:
820 MF_AddHandle(ht
, handles
, CreatePalette((LPLOGPALETTE
)mr
->rdParm
));
823 case META_SETTEXTALIGN
:
824 SetTextAlign(hdc
, mr
->rdParm
[0]);
827 case META_SELECTPALETTE
:
828 GDISelectPalette(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]), mr
->rdParm
[0]);
831 case META_SETMAPPERFLAGS
:
832 SetMapperFlags(hdc
, MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
835 case META_REALIZEPALETTE
:
836 GDIRealizePalette(hdc
);
840 switch (mr
->rdParm
[0]) {
841 case GETSCALINGFACTOR
: /* get function ... would just NULL dereference */
842 case GETPHYSPAGESIZE
:
843 case GETPRINTINGOFFSET
:
846 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
849 Escape(hdc
, mr
->rdParm
[0], mr
->rdParm
[1], (LPCSTR
)&mr
->rdParm
[2], NULL
);
852 case META_EXTTEXTOUT
:
853 MF_Play_MetaExtTextOut( hdc
, mr
);
856 case META_STRETCHDIB
:
858 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[11]);
859 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, mr
->rdParm
[2] );
860 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[10], (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
861 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
862 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], bits
, info
,
863 mr
->rdParm
[2],MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
867 case META_DIBSTRETCHBLT
:
869 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[10]);
870 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size( info
, DIB_RGB_COLORS
);
871 StretchDIBits( hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
872 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
873 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2], bits
, info
,
874 DIB_RGB_COLORS
,MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
878 case META_STRETCHBLT
:
880 HDC hdcSrc
= CreateCompatibleDC(hdc
);
881 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[10], /*Width */
882 mr
->rdParm
[11], /*Height*/
883 mr
->rdParm
[13], /*Planes*/
884 mr
->rdParm
[14], /*BitsPixel*/
885 &mr
->rdParm
[15]); /*bits*/
886 SelectObject(hdcSrc
,hbitmap
);
887 StretchBlt(hdc
, (SHORT
)mr
->rdParm
[9], (SHORT
)mr
->rdParm
[8],
888 (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6],
889 hdcSrc
, (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4],
890 (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
891 MAKELONG(mr
->rdParm
[0],mr
->rdParm
[1]));
898 HDC hdcSrc
= CreateCompatibleDC(hdc
);
899 HBITMAP hbitmap
= CreateBitmap(mr
->rdParm
[7]/*Width */,
900 mr
->rdParm
[8]/*Height*/,
901 mr
->rdParm
[10]/*Planes*/,
902 mr
->rdParm
[11]/*BitsPixel*/,
903 &mr
->rdParm
[12]/*bits*/);
904 SelectObject(hdcSrc
,hbitmap
);
905 BitBlt(hdc
,(SHORT
)mr
->rdParm
[6],(SHORT
)mr
->rdParm
[5],
906 (SHORT
)mr
->rdParm
[4],(SHORT
)mr
->rdParm
[3],
907 hdcSrc
, (SHORT
)mr
->rdParm
[2],(SHORT
)mr
->rdParm
[1],
908 MAKELONG(0,mr
->rdParm
[0]));
913 case META_CREATEREGION
:
915 HRGN hrgn
= CreateRectRgn(0,0,0,0);
917 MF_Play_MetaCreateRegion(mr
, hrgn
);
918 MF_AddHandle(ht
, handles
, hrgn
);
922 case META_FILLREGION
:
923 FillRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[1]),
924 *(ht
->objectHandle
+ mr
->rdParm
[0]));
927 case META_FRAMEREGION
:
928 FrameRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[3]),
929 *(ht
->objectHandle
+ mr
->rdParm
[2]),
930 (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
933 case META_INVERTREGION
:
934 InvertRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
937 case META_PAINTREGION
:
938 PaintRgn(hdc
, *(ht
->objectHandle
+ mr
->rdParm
[0]));
941 case META_SELECTCLIPREGION
:
945 if (mr
->rdParm
[0]) hrgn
= *(ht
->objectHandle
+ mr
->rdParm
[0]);
946 SelectClipRgn(hdc
, hrgn
);
950 case META_DIBCREATEPATTERNBRUSH
:
951 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
952 but there's no difference */
953 MF_AddHandle(ht
, handles
, CreateDIBPatternBrushPt( mr
->rdParm
+ 2, mr
->rdParm
[1] ));
957 /* In practice I've found that there are two layouts for
958 META_DIBBITBLT, one (the first here) is the usual one when a src
959 dc is actually passed to it, the second occurs when the src dc is
960 passed in as NULL to the creating BitBlt. As the second case has
961 no dib, a size check will suffice to distinguish.
963 Caolan.McNamara@ul.ie */
965 if (mr
->rdSize
> 12) {
966 LPBITMAPINFO info
= (LPBITMAPINFO
) &(mr
->rdParm
[8]);
967 LPSTR bits
= (LPSTR
)info
+ bitmap_info_size(info
, mr
->rdParm
[0]);
969 StretchDIBits(hdc
, (SHORT
)mr
->rdParm
[7], (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
970 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3], (SHORT
)mr
->rdParm
[2],
971 (SHORT
)mr
->rdParm
[5], (SHORT
)mr
->rdParm
[4], bits
, info
,
972 DIB_RGB_COLORS
, MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
974 else /* equivalent to a PatBlt */
975 PatBlt(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
976 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
977 MAKELONG(mr
->rdParm
[0], mr
->rdParm
[1]));
980 case META_SETTEXTCHAREXTRA
:
981 SetTextCharacterExtra(hdc
, (SHORT
)mr
->rdParm
[0]);
984 case META_SETTEXTJUSTIFICATION
:
985 SetTextJustification(hdc
, (SHORT
)mr
->rdParm
[1], (SHORT
)mr
->rdParm
[0]);
988 case META_EXTFLOODFILL
:
989 ExtFloodFill(hdc
, (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
990 MAKELONG(mr
->rdParm
[1], mr
->rdParm
[2]),
994 case META_SETDIBTODEV
:
996 BITMAPINFO
*info
= (BITMAPINFO
*) &(mr
->rdParm
[9]);
997 char *bits
= (char *)info
+ bitmap_info_size( info
, mr
->rdParm
[0] );
998 SetDIBitsToDevice(hdc
, (SHORT
)mr
->rdParm
[8], (SHORT
)mr
->rdParm
[7],
999 (SHORT
)mr
->rdParm
[6], (SHORT
)mr
->rdParm
[5],
1000 (SHORT
)mr
->rdParm
[4], (SHORT
)mr
->rdParm
[3],
1001 mr
->rdParm
[2], mr
->rdParm
[1], bits
, info
,
1006 #define META_UNIMP(x) case x: \
1007 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1009 META_UNIMP(META_DRAWTEXT
)
1010 META_UNIMP(META_ANIMATEPALETTE
)
1011 META_UNIMP(META_SETPALENTRIES
)
1012 META_UNIMP(META_RESIZEPALETTE
)
1013 META_UNIMP(META_RESETDC
)
1014 META_UNIMP(META_STARTDOC
)
1015 META_UNIMP(META_STARTPAGE
)
1016 META_UNIMP(META_ENDPAGE
)
1017 META_UNIMP(META_ABORTDOC
)
1018 META_UNIMP(META_ENDDOC
)
1019 META_UNIMP(META_CREATEBRUSH
)
1020 META_UNIMP(META_CREATEBITMAPINDIRECT
)
1021 META_UNIMP(META_CREATEBITMAP
)
1025 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr
->rdFunction
);
1031 /******************************************************************
1032 * SetMetaFileBitsEx (GDI32.@)
1034 * Create a metafile from raw data. No checking of the data is performed.
1035 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1038 * size [I] size of metafile, in bytes
1039 * lpData [I] pointer to metafile data
1042 * Success: Handle to metafile.
1045 HMETAFILE WINAPI
SetMetaFileBitsEx( UINT size
, const BYTE
*lpData
)
1047 const METAHEADER
*mh_in
= (const METAHEADER
*)lpData
;
1050 if (size
& 1) return 0;
1052 if (!size
|| mh_in
->mtType
!= METAFILE_MEMORY
|| mh_in
->mtVersion
!= MFVERSION
||
1053 mh_in
->mtHeaderSize
!= sizeof(METAHEADER
) / 2)
1055 SetLastError(ERROR_INVALID_DATA
);
1059 mh_out
= HeapAlloc( GetProcessHeap(), 0, size
);
1062 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1066 memcpy(mh_out
, mh_in
, size
);
1067 mh_out
->mtSize
= size
/ 2;
1068 return MF_Create_HMETAFILE(mh_out
);
1071 /*****************************************************************
1072 * GetMetaFileBitsEx (GDI32.@)
1074 * Get raw metafile data.
1076 * Copies the data from metafile _hmf_ into the buffer _buf_.
1080 * nSize [I] size of buf
1081 * buf [O] buffer to receive raw metafile data
1084 * If _buf_ is zero, returns size of buffer required. Otherwise,
1085 * returns number of bytes copied.
1087 UINT WINAPI
GetMetaFileBitsEx( HMETAFILE hmf
, UINT nSize
, LPVOID buf
)
1089 METAHEADER
*mh
= GDI_GetObjPtr( hmf
, OBJ_METAFILE
);
1091 BOOL mf_copy
= FALSE
;
1093 TRACE("(%p,%d,%p)\n", hmf
, nSize
, buf
);
1094 if (!mh
) return 0; /* FIXME: error code */
1095 if(mh
->mtType
== METAFILE_DISK
)
1097 mh
= MF_LoadDiskBasedMetaFile( mh
);
1100 GDI_ReleaseObj( hmf
);
1105 mfSize
= mh
->mtSize
* 2;
1108 if(mfSize
> nSize
) mfSize
= nSize
;
1109 memmove(buf
, mh
, mfSize
);
1111 if (mf_copy
) HeapFree( GetProcessHeap(), 0, mh
);
1112 GDI_ReleaseObj( hmf
);
1113 TRACE("returning size %d\n", mfSize
);
1117 /******************************************************************
1120 * Helper for GetWinMetaFileBits
1122 * Add the MFCOMMENT record[s] which is essentially a copy
1123 * of the original emf.
1125 static BOOL
add_mf_comment(HDC hdc
, HENHMETAFILE emf
)
1127 DWORD size
= GetEnhMetaFileBits(emf
, 0, NULL
), i
;
1128 BYTE
*bits
, *chunk_data
;
1129 emf_in_wmf_comment
*chunk
= NULL
;
1131 static const DWORD max_chunk_size
= 0x2000;
1133 if(!size
) return FALSE
;
1134 chunk_data
= bits
= HeapAlloc(GetProcessHeap(), 0, size
);
1135 if(!bits
) return FALSE
;
1136 if(!GetEnhMetaFileBits(emf
, size
, bits
)) goto end
;
1138 chunk
= HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(emf_in_wmf_comment
, emf_data
[max_chunk_size
]));
1139 if(!chunk
) goto end
;
1141 chunk
->magic
= WMFC_MAGIC
;
1146 chunk
->checksum
= 0; /* We fixup the first chunk's checksum before returning from GetWinMetaFileBits */
1148 chunk
->num_chunks
= (size
+ max_chunk_size
- 1) / max_chunk_size
;
1149 chunk
->chunk_size
= max_chunk_size
;
1150 chunk
->remaining_size
= size
;
1151 chunk
->emf_size
= size
;
1153 for(i
= 0; i
< chunk
->num_chunks
; i
++)
1155 if(i
== chunk
->num_chunks
- 1) /* last chunk */
1156 chunk
->chunk_size
= chunk
->remaining_size
;
1158 chunk
->remaining_size
-= chunk
->chunk_size
;
1159 memcpy(chunk
->emf_data
, chunk_data
, chunk
->chunk_size
);
1160 chunk_data
+= chunk
->chunk_size
;
1162 if(!Escape(hdc
, MFCOMMENT
, FIELD_OFFSET(emf_in_wmf_comment
, emf_data
[chunk
->chunk_size
]), (char*)chunk
, NULL
))
1167 HeapFree(GetProcessHeap(), 0, chunk
);
1168 HeapFree(GetProcessHeap(), 0, bits
);
1172 /*******************************************************************
1175 * Behaves somewhat differently to MulDiv when the answer is -ve
1176 * and also rounds n.5 towards zero
1178 static INT
muldiv(INT m1
, INT m2
, INT d
)
1182 ret
= ((LONGLONG
)m1
* m2
+ d
/2) / d
; /* Always add d/2 even if ret will be -ve */
1184 if((LONGLONG
)m1
* m2
* 2 == (2 * ret
- 1) * d
) /* If the answer is exactly n.5 round towards zero */
1192 /******************************************************************
1195 * Helper for GetWinMetaFileBits
1197 * Add the SetWindowOrg and SetWindowExt records
1199 static BOOL
set_window(HDC hdc
, HENHMETAFILE emf
, HDC ref_dc
, INT map_mode
)
1201 ENHMETAHEADER header
;
1202 INT horz_res
, vert_res
, horz_size
, vert_size
;
1205 if(!GetEnhMetaFileHeader(emf
, sizeof(header
), &header
)) return FALSE
;
1207 horz_res
= GetDeviceCaps(ref_dc
, HORZRES
);
1208 vert_res
= GetDeviceCaps(ref_dc
, VERTRES
);
1209 horz_size
= GetDeviceCaps(ref_dc
, HORZSIZE
);
1210 vert_size
= GetDeviceCaps(ref_dc
, VERTSIZE
);
1216 case MM_ANISOTROPIC
:
1217 pt
.y
= muldiv(header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1218 pt
.x
= muldiv(header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1221 pt
.y
= muldiv(-header
.rclFrame
.top
, 1, 10) + 1;
1222 pt
.x
= muldiv( header
.rclFrame
.left
, 1, 10);
1225 pt
.y
= -header
.rclFrame
.top
+ 1;
1226 pt
.x
= (header
.rclFrame
.left
>= 0) ? header
.rclFrame
.left
: header
.rclFrame
.left
+ 1; /* See the tests */
1229 pt
.y
= muldiv(-header
.rclFrame
.top
, 10, 254) + 1;
1230 pt
.x
= muldiv( header
.rclFrame
.left
, 10, 254);
1233 pt
.y
= muldiv(-header
.rclFrame
.top
, 100, 254) + 1;
1234 pt
.x
= muldiv( header
.rclFrame
.left
, 100, 254);
1237 pt
.y
= muldiv(-header
.rclFrame
.top
, 72 * 20, 2540) + 1;
1238 pt
.x
= muldiv( header
.rclFrame
.left
, 72 * 20, 2540);
1241 WARN("Unknown map mode %d\n", map_mode
);
1244 SetWindowOrgEx(hdc
, pt
.x
, pt
.y
, NULL
);
1246 pt
.x
= muldiv(header
.rclFrame
.right
- header
.rclFrame
.left
, horz_res
, horz_size
* 100);
1247 pt
.y
= muldiv(header
.rclFrame
.bottom
- header
.rclFrame
.top
, vert_res
, vert_size
* 100);
1248 SetWindowExtEx(hdc
, pt
.x
, pt
.y
, NULL
);
1252 /******************************************************************
1253 * GetWinMetaFileBits [GDI32.@]
1255 UINT WINAPI
GetWinMetaFileBits(HENHMETAFILE hemf
,
1256 UINT cbBuffer
, LPBYTE lpbBuffer
,
1257 INT map_mode
, HDC hdcRef
)
1261 UINT ret
, full_size
;
1264 GetClipBox(hdcRef
, &rc
);
1266 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf
, cbBuffer
, lpbBuffer
,
1267 map_mode
, hdcRef
, wine_dbgstr_rect(&rc
));
1269 hdcmf
= CreateMetaFileW(NULL
);
1271 add_mf_comment(hdcmf
, hemf
);
1272 SetMapMode(hdcmf
, map_mode
);
1273 if(!set_window(hdcmf
, hemf
, hdcRef
, map_mode
))
1276 PlayEnhMetaFile(hdcmf
, hemf
, &rc
);
1277 hmf
= CloseMetaFile(hdcmf
);
1278 full_size
= GetMetaFileBitsEx(hmf
, 0, NULL
);
1279 ret
= GetMetaFileBitsEx(hmf
, cbBuffer
, lpbBuffer
);
1280 DeleteMetaFile(hmf
);
1282 if(ret
&& ret
== full_size
&& lpbBuffer
) /* fixup checksum, but only if retrieving all of the bits */
1285 METARECORD
*comment_rec
= (METARECORD
*)(lpbBuffer
+ sizeof(METAHEADER
));
1288 for(i
= 0; i
< full_size
/ 2; i
++)
1289 checksum
+= ((WORD
*)lpbBuffer
)[i
];
1290 comment_rec
->rdParm
[8] = ~checksum
+ 1;
1295 DeleteMetaFile(CloseMetaFile(hdcmf
));
1299 /******************************************************************
1300 * MF_Play_MetaCreateRegion
1302 * Handles META_CREATEREGION for PlayMetaFileRecord().
1304 * The layout of the record looks something like this:
1309 * 2 Looks like a handle? - not constant
1311 * 4 Total number of bytes
1312 * 5 No. of separate bands = n [see below]
1313 * 6 Largest number of x co-ords in a band
1314 * 7-10 Bounding box x1 y1 x2 y2
1317 * Regions are divided into bands that are uniform in the
1318 * y-direction. Each band consists of pairs of on/off x-coords and is
1320 * m y0 y1 x1 x2 x3 ... xm m
1321 * into successive rdParm[]s.
1323 * This is probably just a dump of the internal RGNOBJ?
1329 static BOOL
MF_Play_MetaCreateRegion( METARECORD
*mr
, HRGN hrgn
)
1334 HRGN hrgn2
= CreateRectRgn( 0, 0, 0, 0 );
1336 for(band
= 0, start
= &(mr
->rdParm
[11]); band
< mr
->rdParm
[5];
1337 band
++, start
= end
+ 1) {
1338 if(*start
/ 2 != (*start
+ 1) / 2) {
1339 WARN("Delimiter not even.\n");
1340 DeleteObject( hrgn2
);
1344 end
= start
+ *start
+ 3;
1345 if(end
> (WORD
*)mr
+ mr
->rdSize
) {
1346 WARN("End points outside record.\n");
1347 DeleteObject( hrgn2
);
1351 if(*start
!= *end
) {
1352 WARN("Mismatched delimiters.\n");
1353 DeleteObject( hrgn2
);
1357 y0
= *(INT16
*)(start
+ 1);
1358 y1
= *(INT16
*)(start
+ 2);
1359 for(pair
= 0; pair
< *start
/ 2; pair
++) {
1360 SetRectRgn( hrgn2
, *(INT16
*)(start
+ 3 + 2*pair
), y0
,
1361 *(INT16
*)(start
+ 4 + 2*pair
), y1
);
1362 CombineRgn(hrgn
, hrgn
, hrgn2
, RGN_OR
);
1365 DeleteObject( hrgn2
);
1370 /******************************************************************
1371 * MF_Play_MetaExtTextOut
1373 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1376 static BOOL
MF_Play_MetaExtTextOut(HDC hdc
, METARECORD
*mr
)
1385 BOOL isrect
= mr
->rdParm
[3] & (ETO_OPAQUE
| ETO_CLIPPED
);
1387 s1
= mr
->rdParm
[2]; /* String length */
1388 len
= sizeof(METARECORD
) + (((s1
+ 1) >> 1) * 2) + 2 * sizeof(short)
1389 + sizeof(UINT16
) + (isrect
? 4 * sizeof(SHORT
) : 0);
1390 /* rec len without dx array */
1392 sot
= (LPSTR
)&mr
->rdParm
[4]; /* start_of_text */
1395 rect
.left
= (SHORT
)mr
->rdParm
[4];
1396 rect
.top
= (SHORT
)mr
->rdParm
[5];
1397 rect
.right
= (SHORT
)mr
->rdParm
[6];
1398 rect
.bottom
= (SHORT
)mr
->rdParm
[7];
1399 sot
+= 4 * sizeof(SHORT
); /* there is a rectangle, so add offset */
1402 if (mr
->rdSize
== len
/ 2)
1403 dxx
= NULL
; /* determine if array is present */
1405 if (mr
->rdSize
== (len
+ s1
* sizeof(INT16
)) / 2)
1407 dxx
= (SHORT
*)(sot
+(((s1
+1)>>1)*2));
1408 dx
= HeapAlloc( GetProcessHeap(), 0, s1
*sizeof(INT
));
1409 if (dx
) for (i
= 0; i
< s1
; i
++) dx
[i
] = dxx
[i
];
1412 TRACE("%s len: %d\n", sot
, mr
->rdSize
);
1413 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1414 len
, s1
, mr
->rdSize
, mr
->rdParm
[3]);
1415 dxx
= NULL
; /* shouldn't happen -- but if, we continue with NULL */
1418 (SHORT
)mr
->rdParm
[1], /* X position */
1419 (SHORT
)mr
->rdParm
[0], /* Y position */
1420 mr
->rdParm
[3], /* options */
1421 &rect
, /* rectangle */
1423 s1
, dx
); /* length, dx array */
1426 TRACE("%s len: %d dx0: %d\n", sot
, mr
->rdSize
, dx
[0]);
1427 HeapFree( GetProcessHeap(), 0, dx
);