gdi: Filter GETSCALINGFACTOR and SETABORTDOC proc in metafile
[wine/multimedia.git] / dlls / gdi / metafile.c
blob55c82969500f6158985191cf466aa2f9a847346e
1 /*
2 * Metafile functions
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * NOTES
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 indentical 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
38 * the memory.
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.
45 * HDMD - 14/4/1999
48 #include "config.h"
50 #include <string.h>
51 #include <fcntl.h>
53 #include "gdi.h"
54 #include "winreg.h"
55 #include "winternl.h"
56 #include "gdi_private.h"
57 #include "wine/debug.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
61 #include "pshpack1.h"
62 typedef struct
64 DWORD dw1, dw2, dw3;
65 WORD w4;
66 CHAR filename[0x100];
67 } METAHEADERDISK;
68 #include "poppack.h"
70 typedef struct
72 GDIOBJHDR header;
73 METAHEADER *mh;
74 } METAFILEOBJ;
77 /******************************************************************
78 * MF_AddHandle
80 * Add a handle to an external handle table and return the index
82 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
84 int i;
86 for (i = 0; i < htlen; i++)
88 if (*(ht->objectHandle + i) == 0)
90 *(ht->objectHandle + i) = hobj;
91 return i;
94 return -1;
98 /******************************************************************
99 * MF_Create_HMETATFILE
101 * Creates a (32 bit) HMETAFILE object from a METAHEADER
103 * HMETAFILEs are GDI objects.
105 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
107 HMETAFILE hmf = 0;
108 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
109 (HGDIOBJ *)&hmf, NULL );
110 if (metaObj)
112 metaObj->mh = mh;
113 GDI_ReleaseObj( hmf );
115 return hmf;
118 /******************************************************************
119 * MF_GetMetaHeader
121 * Returns ptr to METAHEADER associated with HMETAFILE
123 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
125 METAHEADER *ret = NULL;
126 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
127 if (metaObj)
129 ret = metaObj->mh;
130 GDI_ReleaseObj( hmf );
132 return ret;
135 /******************************************************************
136 * convert_points
138 * Convert an array of POINT16 to an array of POINT.
139 * Result must be freed by caller.
141 static POINT *convert_points( UINT count, POINT16 *pt16 )
143 UINT i;
144 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
145 if (ret)
147 for (i = 0; i < count; i++)
149 ret[i].x = pt16[i].x;
150 ret[i].y = pt16[i].y;
153 return ret;
156 /******************************************************************
157 * DeleteMetaFile (GDI32.@)
159 * Delete a memory-based metafile.
162 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
164 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
165 if (!metaObj) return FALSE;
166 HeapFree( GetProcessHeap(), 0, metaObj->mh );
167 GDI_FreeObject( hmf, metaObj );
168 return TRUE;
171 /******************************************************************
172 * MF_ReadMetaFile
174 * Returns a pointer to a memory based METAHEADER read in from file HFILE
177 METAHEADER *MF_ReadMetaFile(HANDLE hfile)
179 METAHEADER *mh;
180 DWORD BytesRead, size;
182 size = sizeof(METAHEADER);
183 mh = HeapAlloc( GetProcessHeap(), 0, size );
184 if(!mh) return NULL;
185 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
186 BytesRead != size) {
187 HeapFree( GetProcessHeap(), 0, mh );
188 return NULL;
190 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
191 mh->mtHeaderSize != size / 2)
193 HeapFree( GetProcessHeap(), 0, mh );
194 return NULL;
196 size = mh->mtSize * 2;
197 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
198 if(!mh) return NULL;
199 size -= sizeof(METAHEADER);
200 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
201 NULL) == 0 ||
202 BytesRead != size) {
203 HeapFree( GetProcessHeap(), 0, mh );
204 return NULL;
207 if (mh->mtType != METAFILE_MEMORY) {
208 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
209 mh->mtType = METAFILE_MEMORY;
211 return mh;
214 /******************************************************************
215 * GetMetaFileA (GDI32.@)
217 * Read a metafile from a file. Returns handle to a memory-based metafile.
219 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
221 METAHEADER *mh;
222 HANDLE hFile;
224 TRACE("%s\n", lpFilename);
226 if(!lpFilename)
227 return 0;
229 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
230 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
231 return 0;
233 mh = MF_ReadMetaFile(hFile);
234 CloseHandle(hFile);
235 if(!mh) return 0;
236 return MF_Create_HMETAFILE( mh );
239 /******************************************************************
240 * GetMetaFileW (GDI32.@)
242 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
244 METAHEADER *mh;
245 HANDLE hFile;
247 TRACE("%s\n", debugstr_w(lpFilename));
249 if(!lpFilename)
250 return 0;
252 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
253 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
254 return 0;
256 mh = MF_ReadMetaFile(hFile);
257 CloseHandle(hFile);
258 if(!mh) return 0;
259 return MF_Create_HMETAFILE( mh );
263 /******************************************************************
264 * MF_LoadDiskBasedMetaFile
266 * Creates a new memory-based metafile from a disk-based one.
268 METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
270 METAHEADERDISK *mhd;
271 HANDLE hfile;
272 METAHEADER *mh2;
274 if(mh->mtType != METAFILE_DISK) {
275 ERR("Not a disk based metafile\n");
276 return NULL;
278 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
280 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
281 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
282 WARN("Can't open file of disk based metafile\n");
283 return NULL;
285 mh2 = MF_ReadMetaFile(hfile);
286 CloseHandle(hfile);
287 return mh2;
290 /******************************************************************
291 * MF_CreateMetaHeaderDisk
293 * Take a memory based METAHEADER and change it to a disk based METAHEADER
294 * assosiated with filename. Note: Trashes contents of old one.
296 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
298 METAHEADERDISK *mhd;
300 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
301 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
302 mh->mtType = METAFILE_DISK;
303 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
305 if( uni )
306 WideCharToMultiByte(CP_ACP, 0, filename, -1,
307 mhd->filename, sizeof mhd->filename, NULL, NULL);
308 else
309 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
310 return mh;
313 /******************************************************************
314 * CopyMetaFileW (GDI32.@)
316 * Copies the metafile corresponding to hSrcMetaFile to either
317 * a disk file, if a filename is given, or to a new memory based
318 * metafile, if lpFileName is NULL.
320 * PARAMS
321 * hSrcMetaFile [I] handle of metafile to copy
322 * lpFilename [I] filename if copying to a file
324 * RETURNS
325 * Handle to metafile copy on success, NULL on failure.
327 * BUGS
328 * Copying to disk returns NULL even if successful.
330 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
332 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
333 METAHEADER *mh2 = NULL;
334 HANDLE hFile;
336 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
338 if(!mh) return 0;
340 if(mh->mtType == METAFILE_DISK)
341 mh2 = MF_LoadDiskBasedMetaFile(mh);
342 else {
343 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
344 memcpy( mh2, mh, mh->mtSize * 2 );
347 if(lpFilename) { /* disk based metafile */
348 DWORD w;
349 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
350 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
351 HeapFree( GetProcessHeap(), 0, mh2 );
352 return 0;
354 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
355 CloseHandle(hFile);
358 return MF_Create_HMETAFILE( mh2 );
362 /******************************************************************
363 * CopyMetaFileA (GDI32.@)
365 * See CopyMetaFileW.
367 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
369 UNICODE_STRING lpFilenameW;
370 HMETAFILE ret = 0;
372 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
373 else lpFilenameW.Buffer = NULL;
375 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
376 if (lpFilenameW.Buffer)
377 RtlFreeUnicodeString(&lpFilenameW);
378 return ret;
381 /*******************************************************************
382 * MF_PlayMetaFile
384 * Helper for PlayMetaFile
386 BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
389 METARECORD *mr;
390 HANDLETABLE *ht;
391 unsigned int offset = 0;
392 WORD i;
393 HPEN hPen;
394 HBRUSH hBrush;
395 HFONT hFont;
396 BOOL loaded = FALSE;
398 if (!mh) return FALSE;
399 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
400 mh = MF_LoadDiskBasedMetaFile(mh);
401 if(!mh) return FALSE;
402 loaded = TRUE;
405 /* save the current pen, brush and font */
406 hPen = GetCurrentObject(hdc, OBJ_PEN);
407 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
408 hFont = GetCurrentObject(hdc, OBJ_FONT);
410 /* create the handle table */
411 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
412 sizeof(HANDLETABLE) * mh->mtNoObjects);
413 if(!ht) return FALSE;
415 /* loop through metafile playing records */
416 offset = mh->mtHeaderSize * 2;
417 while (offset < mh->mtSize * 2)
419 mr = (METARECORD *)((char *)mh + offset);
420 TRACE("offset=%04x,size=%08lx\n",
421 offset, mr->rdSize);
422 if (!mr->rdSize) {
423 TRACE(
424 "Entry got size 0 at offset %d, total mf length is %ld\n",
425 offset,mh->mtSize*2);
426 break; /* would loop endlessly otherwise */
428 offset += mr->rdSize * 2;
429 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
432 SelectObject(hdc, hBrush);
433 SelectObject(hdc, hPen);
434 SelectObject(hdc, hFont);
436 /* free objects in handle table */
437 for(i = 0; i < mh->mtNoObjects; i++)
438 if(*(ht->objectHandle + i) != 0)
439 DeleteObject(*(ht->objectHandle + i));
441 /* free handle table */
442 HeapFree( GetProcessHeap(), 0, ht );
443 if(loaded)
444 HeapFree( GetProcessHeap(), 0, mh );
445 return TRUE;
448 /******************************************************************
449 * PlayMetaFile (GDI32.@)
451 * Renders the metafile specified by hmf in the DC specified by
452 * hdc. Returns FALSE on failure, TRUE on success.
454 * PARAMS
455 * hdc [I] handle of DC to render in
456 * hmf [I] handle of metafile to render
458 * RETURNS
459 * Success: TRUE
460 * Failure: FALSE
462 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
464 METAHEADER *mh = MF_GetMetaHeader( hmf );
465 return MF_PlayMetaFile( hdc, mh );
468 /******************************************************************
469 * EnumMetaFile (GDI32.@)
471 * Loop through the metafile records in hmf, calling the user-specified
472 * function for each one, stopping when the user's function returns FALSE
473 * (which is considered to be failure)
474 * or when no records are left (which is considered to be success).
476 * RETURNS
477 * TRUE on success, FALSE on failure.
479 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
481 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
482 METARECORD *mr;
483 HANDLETABLE *ht;
484 BOOL result = TRUE;
485 int i;
486 unsigned int offset = 0;
487 HPEN hPen;
488 HBRUSH hBrush;
489 HFONT hFont;
491 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
492 if (!mh) return 0;
493 if(mh->mtType == METAFILE_DISK)
495 /* Create a memory-based copy */
496 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
497 mh = mhTemp;
500 /* save the current pen, brush and font */
501 hPen = GetCurrentObject(hdc, OBJ_PEN);
502 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
503 hFont = GetCurrentObject(hdc, OBJ_FONT);
505 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
506 sizeof(HANDLETABLE) * mh->mtNoObjects);
508 /* loop through metafile records */
509 offset = mh->mtHeaderSize * 2;
511 while (offset < (mh->mtSize * 2))
513 mr = (METARECORD *)((char *)mh + offset);
514 if(mr->rdFunction == META_EOF) {
515 TRACE("Got META_EOF so stopping\n");
516 break;
518 TRACE("Calling EnumFunc with record type %x\n",
519 mr->rdFunction);
520 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
522 result = FALSE;
523 break;
526 offset += (mr->rdSize * 2);
529 /* restore pen, brush and font */
530 SelectObject(hdc, hBrush);
531 SelectObject(hdc, hPen);
532 SelectObject(hdc, hFont);
534 /* free objects in handle table */
535 for(i = 0; i < mh->mtNoObjects; i++)
536 if(*(ht->objectHandle + i) != 0)
537 DeleteObject(*(ht->objectHandle + i));
539 /* free handle table */
540 HeapFree( GetProcessHeap(), 0, ht);
541 /* free a copy of metafile */
542 HeapFree( GetProcessHeap(), 0, mhTemp );
543 return result;
546 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
547 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
548 /******************************************************************
549 * PlayMetaFileRecord (GDI32.@)
551 * Render a single metafile record specified by *mr in the DC hdc, while
552 * using the handle table *ht, of length handles,
553 * to store metafile objects.
555 * BUGS
556 * The following metafile records are unimplemented:
558 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
559 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
560 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
562 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
564 short s1;
565 POINT *pt;
566 BITMAPINFOHEADER *infohdr;
568 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
570 switch (mr->rdFunction)
572 case META_EOF:
573 break;
575 case META_DELETEOBJECT:
576 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
577 *(ht->objectHandle + mr->rdParm[0]) = 0;
578 break;
580 case META_SETBKCOLOR:
581 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
582 break;
584 case META_SETBKMODE:
585 SetBkMode(hdc, mr->rdParm[0]);
586 break;
588 case META_SETMAPMODE:
589 SetMapMode(hdc, mr->rdParm[0]);
590 break;
592 case META_SETROP2:
593 SetROP2(hdc, mr->rdParm[0]);
594 break;
596 case META_SETRELABS:
597 SetRelAbs(hdc, mr->rdParm[0]);
598 break;
600 case META_SETPOLYFILLMODE:
601 SetPolyFillMode(hdc, mr->rdParm[0]);
602 break;
604 case META_SETSTRETCHBLTMODE:
605 SetStretchBltMode(hdc, mr->rdParm[0]);
606 break;
608 case META_SETTEXTCOLOR:
609 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
610 break;
612 case META_SETWINDOWORG:
613 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
614 break;
616 case META_SETWINDOWEXT:
617 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
618 break;
620 case META_SETVIEWPORTORG:
621 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
622 break;
624 case META_SETVIEWPORTEXT:
625 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
626 break;
628 case META_OFFSETWINDOWORG:
629 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
630 break;
632 case META_SCALEWINDOWEXT:
633 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
634 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
635 break;
637 case META_OFFSETVIEWPORTORG:
638 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
639 break;
641 case META_SCALEVIEWPORTEXT:
642 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
643 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
644 break;
646 case META_LINETO:
647 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
648 break;
650 case META_MOVETO:
651 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
652 break;
654 case META_EXCLUDECLIPRECT:
655 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
656 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
657 break;
659 case META_INTERSECTCLIPRECT:
660 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
661 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
662 break;
664 case META_ARC:
665 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
666 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
667 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
668 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
669 break;
671 case META_ELLIPSE:
672 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
673 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
674 break;
676 case META_FLOODFILL:
677 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
678 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
679 break;
681 case META_PIE:
682 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
683 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
684 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
685 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
686 break;
688 case META_RECTANGLE:
689 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
690 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
691 break;
693 case META_ROUNDRECT:
694 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
695 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
696 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
697 break;
699 case META_PATBLT:
700 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
701 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
702 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
703 break;
705 case META_SAVEDC:
706 SaveDC(hdc);
707 break;
709 case META_SETPIXEL:
710 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
711 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
712 break;
714 case META_OFFSETCLIPRGN:
715 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
716 break;
718 case META_TEXTOUT:
719 s1 = mr->rdParm[0];
720 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
721 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
722 (char *)(mr->rdParm + 1), s1);
723 break;
725 case META_POLYGON:
726 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
728 Polygon(hdc, pt, mr->rdParm[0]);
729 HeapFree( GetProcessHeap(), 0, pt );
731 break;
733 case META_POLYPOLYGON:
735 UINT i, total;
736 SHORT *counts = (SHORT *)(mr->rdParm + 1);
738 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
739 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
740 if (pt)
742 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
743 if (cnt32)
745 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
746 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
747 HeapFree( GetProcessHeap(), 0, cnt32 );
750 HeapFree( GetProcessHeap(), 0, pt );
752 break;
754 case META_POLYLINE:
755 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
757 Polyline( hdc, pt, mr->rdParm[0] );
758 HeapFree( GetProcessHeap(), 0, pt );
760 break;
762 case META_RESTOREDC:
763 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
764 break;
766 case META_SELECTOBJECT:
767 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
768 break;
770 case META_CHORD:
771 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
772 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
773 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
774 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
775 break;
777 case META_CREATEPATTERNBRUSH:
778 switch (mr->rdParm[0])
780 case BS_PATTERN:
781 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
782 MF_AddHandle(ht, handles,
783 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
784 infohdr->biHeight,
785 infohdr->biPlanes,
786 infohdr->biBitCount,
787 (LPSTR)(mr->rdParm +
788 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
789 break;
791 case BS_DIBPATTERN:
792 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
793 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
794 break;
796 default:
797 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
798 mr->rdParm[0]);
799 break;
801 break;
803 case META_CREATEPENINDIRECT:
805 LOGPEN pen;
806 pen.lopnStyle = mr->rdParm[0];
807 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
808 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
809 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
810 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
812 break;
814 case META_CREATEFONTINDIRECT:
816 LOGFONTA font;
817 font.lfHeight = (SHORT)mr->rdParm[0];
818 font.lfWidth = (SHORT)mr->rdParm[1];
819 font.lfEscapement = (SHORT)mr->rdParm[2];
820 font.lfOrientation = (SHORT)mr->rdParm[3];
821 font.lfWeight = (SHORT)mr->rdParm[4];
822 font.lfItalic = LOBYTE(mr->rdParm[5]);
823 font.lfUnderline = HIBYTE(mr->rdParm[5]);
824 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
825 font.lfCharSet = HIBYTE(mr->rdParm[6]);
826 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
827 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
828 font.lfQuality = LOBYTE(mr->rdParm[8]);
829 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
830 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
831 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
833 break;
835 case META_CREATEBRUSHINDIRECT:
837 LOGBRUSH brush;
838 brush.lbStyle = mr->rdParm[0];
839 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
840 brush.lbHatch = mr->rdParm[3];
841 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
843 break;
845 case META_CREATEPALETTE:
846 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
847 break;
849 case META_SETTEXTALIGN:
850 SetTextAlign(hdc, mr->rdParm[0]);
851 break;
853 case META_SELECTPALETTE:
854 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
855 break;
857 case META_SETMAPPERFLAGS:
858 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
859 break;
861 case META_REALIZEPALETTE:
862 GDIRealizePalette(hdc);
863 break;
865 case META_ESCAPE:
866 switch (mr->rdParm[0]) {
867 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
868 return FALSE;
869 case SETABORTPROC:
870 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
871 return FALSE;
873 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
874 break;
876 case META_EXTTEXTOUT:
877 MF_Play_MetaExtTextOut( hdc, mr );
878 break;
880 case META_STRETCHDIB:
882 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
883 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
884 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
885 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
886 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
887 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
889 break;
891 case META_DIBSTRETCHBLT:
893 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
894 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
895 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
896 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
897 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
898 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
900 break;
902 case META_STRETCHBLT:
904 HDC hdcSrc = CreateCompatibleDC(hdc);
905 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
906 mr->rdParm[11], /*Height*/
907 mr->rdParm[13], /*Planes*/
908 mr->rdParm[14], /*BitsPixel*/
909 (LPSTR)&mr->rdParm[15]); /*bits*/
910 SelectObject(hdcSrc,hbitmap);
911 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
912 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
913 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
914 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
915 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
916 DeleteDC(hdcSrc);
918 break;
920 case META_BITBLT:
922 HDC hdcSrc = CreateCompatibleDC(hdc);
923 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
924 mr->rdParm[8]/*Height*/,
925 mr->rdParm[10]/*Planes*/,
926 mr->rdParm[11]/*BitsPixel*/,
927 (LPSTR)&mr->rdParm[12]/*bits*/);
928 SelectObject(hdcSrc,hbitmap);
929 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
930 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
931 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
932 MAKELONG(0,mr->rdParm[0]));
933 DeleteDC(hdcSrc);
935 break;
937 case META_CREATEREGION:
939 HRGN hrgn = CreateRectRgn(0,0,0,0);
941 MF_Play_MetaCreateRegion(mr, hrgn);
942 MF_AddHandle(ht, handles, hrgn);
944 break;
946 case META_FILLREGION:
947 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
948 *(ht->objectHandle + mr->rdParm[0]));
949 break;
951 case META_FRAMEREGION:
952 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
953 *(ht->objectHandle + mr->rdParm[2]),
954 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
955 break;
957 case META_INVERTREGION:
958 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
959 break;
961 case META_PAINTREGION:
962 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
963 break;
965 case META_SELECTCLIPREGION:
967 HRGN hrgn = 0;
969 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
970 SelectClipRgn(hdc, hrgn);
972 break;
974 case META_DIBCREATEPATTERNBRUSH:
975 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
976 but there's no difference */
977 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
978 break;
980 case META_DIBBITBLT:
981 /* In practice I've found that there are two layouts for
982 META_DIBBITBLT, one (the first here) is the usual one when a src
983 dc is actually passed to it, the second occurs when the src dc is
984 passed in as NULL to the creating BitBlt. As the second case has
985 no dib, a size check will suffice to distinguish.
987 Caolan.McNamara@ul.ie */
989 if (mr->rdSize > 12) {
990 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
991 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
993 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
994 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
995 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
996 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
998 else /* equivalent to a PatBlt */
999 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1000 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1001 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1002 break;
1004 case META_SETTEXTCHAREXTRA:
1005 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1006 break;
1008 case META_SETTEXTJUSTIFICATION:
1009 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1010 break;
1012 case META_EXTFLOODFILL:
1013 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1014 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1015 mr->rdParm[0]);
1016 break;
1018 case META_SETDIBTODEV:
1020 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1021 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1022 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1023 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1024 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1025 mr->rdParm[2], mr->rdParm[1], bits, info,
1026 mr->rdParm[0]);
1027 break;
1030 #define META_UNIMP(x) case x: \
1031 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1032 break;
1033 META_UNIMP(META_DRAWTEXT)
1034 META_UNIMP(META_ANIMATEPALETTE)
1035 META_UNIMP(META_SETPALENTRIES)
1036 META_UNIMP(META_RESIZEPALETTE)
1037 META_UNIMP(META_RESETDC)
1038 META_UNIMP(META_STARTDOC)
1039 META_UNIMP(META_STARTPAGE)
1040 META_UNIMP(META_ENDPAGE)
1041 META_UNIMP(META_ABORTDOC)
1042 META_UNIMP(META_ENDDOC)
1043 META_UNIMP(META_CREATEBRUSH)
1044 META_UNIMP(META_CREATEBITMAPINDIRECT)
1045 META_UNIMP(META_CREATEBITMAP)
1046 #undef META_UNIMP
1048 default:
1049 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1050 return FALSE;
1052 return TRUE;
1055 /******************************************************************
1056 * SetMetaFileBitsEx (GDI32.@)
1058 * Create a metafile from raw data. No checking of the data is performed.
1059 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1061 * PARAMS
1062 * size [I] size of metafile, in bytes
1063 * lpData [I] pointer to metafile data
1065 * RETURNS
1066 * Success: Handle to metafile.
1067 * Failure: NULL.
1069 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1071 METAHEADER *mh = (METAHEADER *)lpData;
1073 if (size & 1) return 0;
1075 if (!size || mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
1076 mh->mtHeaderSize != sizeof(METAHEADER) / 2)
1078 SetLastError(ERROR_INVALID_DATA);
1079 return 0;
1082 mh = HeapAlloc( GetProcessHeap(), 0, size );
1083 if (!mh)
1085 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1086 return 0;
1089 memcpy(mh, lpData, size);
1090 mh->mtSize = size / 2;
1091 return MF_Create_HMETAFILE(mh);
1094 /*****************************************************************
1095 * GetMetaFileBitsEx (GDI32.@)
1097 * Get raw metafile data.
1099 * Copies the data from metafile _hmf_ into the buffer _buf_.
1101 * PARAMS
1102 * hmf [I] metafile
1103 * nSize [I] size of buf
1104 * buf [O] buffer to receive raw metafile data
1106 * RETURNS
1107 * If _buf_ is zero, returns size of buffer required. Otherwise,
1108 * returns number of bytes copied.
1110 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1112 METAHEADER *mh = MF_GetMetaHeader(hmf);
1113 UINT mfSize;
1115 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1116 if (!mh) return 0; /* FIXME: error code */
1117 if(mh->mtType == METAFILE_DISK)
1118 FIXME("Disk-based metafile?\n");
1119 mfSize = mh->mtSize * 2;
1120 if (!buf) {
1121 TRACE("returning size %d\n", mfSize);
1122 return mfSize;
1124 if(mfSize > nSize) mfSize = nSize;
1125 memmove(buf, mh, mfSize);
1126 return mfSize;
1129 /******************************************************************
1130 * GetWinMetaFileBits [GDI32.@]
1132 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1133 UINT cbBuffer, LPBYTE lpbBuffer,
1134 INT fnMapMode, HDC hdcRef)
1136 HDC hdcmf;
1137 HMETAFILE hmf;
1138 UINT ret;
1139 RECT rc;
1140 INT oldMapMode;
1142 GetClipBox(hdcRef, &rc);
1143 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1145 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1146 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1148 hdcmf = CreateMetaFileA(NULL);
1149 PlayEnhMetaFile(hdcmf, hemf, &rc);
1150 hmf = CloseMetaFile(hdcmf);
1151 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1152 DeleteMetaFile(hmf);
1154 SetMapMode(hdcRef, oldMapMode);
1156 return ret;
1159 /******************************************************************
1160 * MF_Play_MetaCreateRegion
1162 * Handles META_CREATEREGION for PlayMetaFileRecord().
1164 * The layout of the record looks something like this:
1166 * rdParm meaning
1167 * 0 Always 0?
1168 * 1 Always 6?
1169 * 2 Looks like a handle? - not constant
1170 * 3 0 or 1 ??
1171 * 4 Total number of bytes
1172 * 5 No. of separate bands = n [see below]
1173 * 6 Largest number of x co-ords in a band
1174 * 7-10 Bounding box x1 y1 x2 y2
1175 * 11-... n bands
1177 * Regions are divided into bands that are uniform in the
1178 * y-direction. Each band consists of pairs of on/off x-coords and is
1179 * written as
1180 * m y0 y1 x1 x2 x3 ... xm m
1181 * into successive rdParm[]s.
1183 * This is probably just a dump of the internal RGNOBJ?
1185 * HDMD - 18/12/97
1189 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1191 WORD band, pair;
1192 WORD *start, *end;
1193 INT16 y0, y1;
1194 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1196 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1197 band++, start = end + 1) {
1198 if(*start / 2 != (*start + 1) / 2) {
1199 WARN("Delimiter not even.\n");
1200 DeleteObject( hrgn2 );
1201 return FALSE;
1204 end = start + *start + 3;
1205 if(end > (WORD *)mr + mr->rdSize) {
1206 WARN("End points outside record.\n");
1207 DeleteObject( hrgn2 );
1208 return FALSE;
1211 if(*start != *end) {
1212 WARN("Mismatched delimiters.\n");
1213 DeleteObject( hrgn2 );
1214 return FALSE;
1217 y0 = *(INT16 *)(start + 1);
1218 y1 = *(INT16 *)(start + 2);
1219 for(pair = 0; pair < *start / 2; pair++) {
1220 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1221 *(INT16 *)(start + 4 + 2*pair), y1 );
1222 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1225 DeleteObject( hrgn2 );
1226 return TRUE;
1230 /******************************************************************
1231 * MF_Play_MetaExtTextOut
1233 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1236 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1238 INT *dx = NULL;
1239 int i;
1240 LPINT16 dxx;
1241 LPSTR sot;
1242 DWORD len;
1243 WORD s1;
1244 RECT rect;
1245 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1247 s1 = mr->rdParm[2]; /* String length */
1248 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1249 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1250 /* rec len without dx array */
1252 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1253 if (isrect)
1255 rect.left = (SHORT)mr->rdParm[4];
1256 rect.top = (SHORT)mr->rdParm[5];
1257 rect.right = (SHORT)mr->rdParm[6];
1258 rect.bottom = (SHORT)mr->rdParm[7];
1259 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1262 if (mr->rdSize == len / 2)
1263 dxx = NULL; /* determine if array present */
1264 else
1265 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1267 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1268 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1269 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1271 else {
1272 TRACE("%s len: %ld\n", sot, mr->rdSize);
1273 WARN("Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1274 len, s1, mr->rdSize, mr->rdParm[3]);
1275 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1277 ExtTextOutA( hdc,
1278 (SHORT)mr->rdParm[1], /* X position */
1279 (SHORT)mr->rdParm[0], /* Y position */
1280 mr->rdParm[3], /* options */
1281 &rect, /* rectangle */
1282 sot, /* string */
1283 s1, dx); /* length, dx array */
1284 if (dx)
1286 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1287 HeapFree( GetProcessHeap(), 0, dx );
1289 return TRUE;