wined3d: Prevent crash in setup_light.
[wine.git] / dlls / gdi / metafile.c
blob96011ff05d263b81ebb41f181bef6b7f82e1009c
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 < 3) { /* catch illegal record sizes */
423 TRACE("Entry got size %ld at offset %d, total mf length is %ld\n",
424 mr->rdSize,offset,mh->mtSize*2);
425 break;
427 offset += mr->rdSize * 2;
428 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
431 SelectObject(hdc, hBrush);
432 SelectObject(hdc, hPen);
433 SelectObject(hdc, hFont);
435 /* free objects in handle table */
436 for(i = 0; i < mh->mtNoObjects; i++)
437 if(*(ht->objectHandle + i) != 0)
438 DeleteObject(*(ht->objectHandle + i));
440 /* free handle table */
441 HeapFree( GetProcessHeap(), 0, ht );
442 if(loaded)
443 HeapFree( GetProcessHeap(), 0, mh );
444 return TRUE;
447 /******************************************************************
448 * PlayMetaFile (GDI32.@)
450 * Renders the metafile specified by hmf in the DC specified by
451 * hdc. Returns FALSE on failure, TRUE on success.
453 * PARAMS
454 * hdc [I] handle of DC to render in
455 * hmf [I] handle of metafile to render
457 * RETURNS
458 * Success: TRUE
459 * Failure: FALSE
461 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
463 METAHEADER *mh = MF_GetMetaHeader( hmf );
464 return MF_PlayMetaFile( hdc, mh );
467 /******************************************************************
468 * EnumMetaFile (GDI32.@)
470 * Loop through the metafile records in hmf, calling the user-specified
471 * function for each one, stopping when the user's function returns FALSE
472 * (which is considered to be failure)
473 * or when no records are left (which is considered to be success).
475 * RETURNS
476 * TRUE on success, FALSE on failure.
478 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
480 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
481 METARECORD *mr;
482 HANDLETABLE *ht;
483 BOOL result = TRUE;
484 int i;
485 unsigned int offset = 0;
486 HPEN hPen;
487 HBRUSH hBrush;
488 HFONT hFont;
490 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
491 if (!mh) return 0;
492 if(mh->mtType == METAFILE_DISK)
494 /* Create a memory-based copy */
495 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
496 mh = mhTemp;
499 /* save the current pen, brush and font */
500 hPen = GetCurrentObject(hdc, OBJ_PEN);
501 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
502 hFont = GetCurrentObject(hdc, OBJ_FONT);
504 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
505 sizeof(HANDLETABLE) * mh->mtNoObjects);
507 /* loop through metafile records */
508 offset = mh->mtHeaderSize * 2;
510 while (offset < (mh->mtSize * 2))
512 mr = (METARECORD *)((char *)mh + offset);
513 if(mr->rdFunction == META_EOF) {
514 TRACE("Got META_EOF so stopping\n");
515 break;
517 TRACE("Calling EnumFunc with record type %x\n",
518 mr->rdFunction);
519 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
521 result = FALSE;
522 break;
525 offset += (mr->rdSize * 2);
528 /* restore pen, brush and font */
529 SelectObject(hdc, hBrush);
530 SelectObject(hdc, hPen);
531 SelectObject(hdc, hFont);
533 /* free objects in handle table */
534 for(i = 0; i < mh->mtNoObjects; i++)
535 if(*(ht->objectHandle + i) != 0)
536 DeleteObject(*(ht->objectHandle + i));
538 /* free handle table */
539 HeapFree( GetProcessHeap(), 0, ht);
540 /* free a copy of metafile */
541 HeapFree( GetProcessHeap(), 0, mhTemp );
542 return result;
545 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
546 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
547 /******************************************************************
548 * PlayMetaFileRecord (GDI32.@)
550 * Render a single metafile record specified by *mr in the DC hdc, while
551 * using the handle table *ht, of length handles,
552 * to store metafile objects.
554 * BUGS
555 * The following metafile records are unimplemented:
557 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
558 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
559 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
561 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
563 short s1;
564 POINT *pt;
565 BITMAPINFOHEADER *infohdr;
567 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
569 switch (mr->rdFunction)
571 case META_EOF:
572 break;
574 case META_DELETEOBJECT:
575 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
576 *(ht->objectHandle + mr->rdParm[0]) = 0;
577 break;
579 case META_SETBKCOLOR:
580 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
581 break;
583 case META_SETBKMODE:
584 SetBkMode(hdc, mr->rdParm[0]);
585 break;
587 case META_SETMAPMODE:
588 SetMapMode(hdc, mr->rdParm[0]);
589 break;
591 case META_SETROP2:
592 SetROP2(hdc, mr->rdParm[0]);
593 break;
595 case META_SETRELABS:
596 SetRelAbs(hdc, mr->rdParm[0]);
597 break;
599 case META_SETPOLYFILLMODE:
600 SetPolyFillMode(hdc, mr->rdParm[0]);
601 break;
603 case META_SETSTRETCHBLTMODE:
604 SetStretchBltMode(hdc, mr->rdParm[0]);
605 break;
607 case META_SETTEXTCOLOR:
608 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
609 break;
611 case META_SETWINDOWORG:
612 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
613 break;
615 case META_SETWINDOWEXT:
616 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
617 break;
619 case META_SETVIEWPORTORG:
620 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
621 break;
623 case META_SETVIEWPORTEXT:
624 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
625 break;
627 case META_OFFSETWINDOWORG:
628 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
629 break;
631 case META_SCALEWINDOWEXT:
632 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
633 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
634 break;
636 case META_OFFSETVIEWPORTORG:
637 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
638 break;
640 case META_SCALEVIEWPORTEXT:
641 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
642 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
643 break;
645 case META_LINETO:
646 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
647 break;
649 case META_MOVETO:
650 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
651 break;
653 case META_EXCLUDECLIPRECT:
654 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
655 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
656 break;
658 case META_INTERSECTCLIPRECT:
659 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
660 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
661 break;
663 case META_ARC:
664 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
665 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
666 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
667 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
668 break;
670 case META_ELLIPSE:
671 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
672 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
673 break;
675 case META_FLOODFILL:
676 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
677 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
678 break;
680 case META_PIE:
681 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
682 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
683 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
684 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
685 break;
687 case META_RECTANGLE:
688 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
689 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
690 break;
692 case META_ROUNDRECT:
693 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
694 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
695 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
696 break;
698 case META_PATBLT:
699 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
700 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
701 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
702 break;
704 case META_SAVEDC:
705 SaveDC(hdc);
706 break;
708 case META_SETPIXEL:
709 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
710 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
711 break;
713 case META_OFFSETCLIPRGN:
714 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
715 break;
717 case META_TEXTOUT:
718 s1 = mr->rdParm[0];
719 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
720 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
721 (char *)(mr->rdParm + 1), s1);
722 break;
724 case META_POLYGON:
725 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
727 Polygon(hdc, pt, mr->rdParm[0]);
728 HeapFree( GetProcessHeap(), 0, pt );
730 break;
732 case META_POLYPOLYGON:
734 UINT i, total;
735 SHORT *counts = (SHORT *)(mr->rdParm + 1);
737 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
738 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
739 if (pt)
741 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
742 if (cnt32)
744 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
745 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
746 HeapFree( GetProcessHeap(), 0, cnt32 );
749 HeapFree( GetProcessHeap(), 0, pt );
751 break;
753 case META_POLYLINE:
754 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
756 Polyline( hdc, pt, mr->rdParm[0] );
757 HeapFree( GetProcessHeap(), 0, pt );
759 break;
761 case META_RESTOREDC:
762 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
763 break;
765 case META_SELECTOBJECT:
766 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
767 break;
769 case META_CHORD:
770 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
771 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
772 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
773 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
774 break;
776 case META_CREATEPATTERNBRUSH:
777 switch (mr->rdParm[0])
779 case BS_PATTERN:
780 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
781 MF_AddHandle(ht, handles,
782 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
783 infohdr->biHeight,
784 infohdr->biPlanes,
785 infohdr->biBitCount,
786 (LPSTR)(mr->rdParm +
787 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
788 break;
790 case BS_DIBPATTERN:
791 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
792 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
793 break;
795 default:
796 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
797 mr->rdParm[0]);
798 break;
800 break;
802 case META_CREATEPENINDIRECT:
804 LOGPEN pen;
805 pen.lopnStyle = mr->rdParm[0];
806 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
807 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
808 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
809 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
811 break;
813 case META_CREATEFONTINDIRECT:
815 LOGFONTA font;
816 font.lfHeight = (SHORT)mr->rdParm[0];
817 font.lfWidth = (SHORT)mr->rdParm[1];
818 font.lfEscapement = (SHORT)mr->rdParm[2];
819 font.lfOrientation = (SHORT)mr->rdParm[3];
820 font.lfWeight = (SHORT)mr->rdParm[4];
821 font.lfItalic = LOBYTE(mr->rdParm[5]);
822 font.lfUnderline = HIBYTE(mr->rdParm[5]);
823 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
824 font.lfCharSet = HIBYTE(mr->rdParm[6]);
825 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
826 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
827 font.lfQuality = LOBYTE(mr->rdParm[8]);
828 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
829 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
830 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
832 break;
834 case META_CREATEBRUSHINDIRECT:
836 LOGBRUSH brush;
837 brush.lbStyle = mr->rdParm[0];
838 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
839 brush.lbHatch = mr->rdParm[3];
840 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
842 break;
844 case META_CREATEPALETTE:
845 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
846 break;
848 case META_SETTEXTALIGN:
849 SetTextAlign(hdc, mr->rdParm[0]);
850 break;
852 case META_SELECTPALETTE:
853 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
854 break;
856 case META_SETMAPPERFLAGS:
857 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
858 break;
860 case META_REALIZEPALETTE:
861 GDIRealizePalette(hdc);
862 break;
864 case META_ESCAPE:
865 switch (mr->rdParm[0]) {
866 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
867 case GETPHYSPAGESIZE:
868 case GETPRINTINGOFFSET:
869 return FALSE;
870 case SETABORTPROC:
871 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
872 return FALSE;
874 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
875 break;
877 case META_EXTTEXTOUT:
878 MF_Play_MetaExtTextOut( hdc, mr );
879 break;
881 case META_STRETCHDIB:
883 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
884 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
885 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
886 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
887 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
888 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
890 break;
892 case META_DIBSTRETCHBLT:
894 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
895 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
896 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
897 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
898 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
899 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
901 break;
903 case META_STRETCHBLT:
905 HDC hdcSrc = CreateCompatibleDC(hdc);
906 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
907 mr->rdParm[11], /*Height*/
908 mr->rdParm[13], /*Planes*/
909 mr->rdParm[14], /*BitsPixel*/
910 (LPSTR)&mr->rdParm[15]); /*bits*/
911 SelectObject(hdcSrc,hbitmap);
912 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
913 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
914 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
915 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
916 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
917 DeleteDC(hdcSrc);
919 break;
921 case META_BITBLT:
923 HDC hdcSrc = CreateCompatibleDC(hdc);
924 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
925 mr->rdParm[8]/*Height*/,
926 mr->rdParm[10]/*Planes*/,
927 mr->rdParm[11]/*BitsPixel*/,
928 (LPSTR)&mr->rdParm[12]/*bits*/);
929 SelectObject(hdcSrc,hbitmap);
930 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
931 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
932 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
933 MAKELONG(0,mr->rdParm[0]));
934 DeleteDC(hdcSrc);
936 break;
938 case META_CREATEREGION:
940 HRGN hrgn = CreateRectRgn(0,0,0,0);
942 MF_Play_MetaCreateRegion(mr, hrgn);
943 MF_AddHandle(ht, handles, hrgn);
945 break;
947 case META_FILLREGION:
948 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
949 *(ht->objectHandle + mr->rdParm[0]));
950 break;
952 case META_FRAMEREGION:
953 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
954 *(ht->objectHandle + mr->rdParm[2]),
955 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
956 break;
958 case META_INVERTREGION:
959 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
960 break;
962 case META_PAINTREGION:
963 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
964 break;
966 case META_SELECTCLIPREGION:
968 HRGN hrgn = 0;
970 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
971 SelectClipRgn(hdc, hrgn);
973 break;
975 case META_DIBCREATEPATTERNBRUSH:
976 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
977 but there's no difference */
978 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
979 break;
981 case META_DIBBITBLT:
982 /* In practice I've found that there are two layouts for
983 META_DIBBITBLT, one (the first here) is the usual one when a src
984 dc is actually passed to it, the second occurs when the src dc is
985 passed in as NULL to the creating BitBlt. As the second case has
986 no dib, a size check will suffice to distinguish.
988 Caolan.McNamara@ul.ie */
990 if (mr->rdSize > 12) {
991 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
992 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
994 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
995 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
996 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
997 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
999 else /* equivalent to a PatBlt */
1000 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1001 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1002 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1003 break;
1005 case META_SETTEXTCHAREXTRA:
1006 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1007 break;
1009 case META_SETTEXTJUSTIFICATION:
1010 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1011 break;
1013 case META_EXTFLOODFILL:
1014 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1015 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1016 mr->rdParm[0]);
1017 break;
1019 case META_SETDIBTODEV:
1021 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1022 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1023 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1024 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1025 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1026 mr->rdParm[2], mr->rdParm[1], bits, info,
1027 mr->rdParm[0]);
1028 break;
1031 #define META_UNIMP(x) case x: \
1032 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1033 break;
1034 META_UNIMP(META_DRAWTEXT)
1035 META_UNIMP(META_ANIMATEPALETTE)
1036 META_UNIMP(META_SETPALENTRIES)
1037 META_UNIMP(META_RESIZEPALETTE)
1038 META_UNIMP(META_RESETDC)
1039 META_UNIMP(META_STARTDOC)
1040 META_UNIMP(META_STARTPAGE)
1041 META_UNIMP(META_ENDPAGE)
1042 META_UNIMP(META_ABORTDOC)
1043 META_UNIMP(META_ENDDOC)
1044 META_UNIMP(META_CREATEBRUSH)
1045 META_UNIMP(META_CREATEBITMAPINDIRECT)
1046 META_UNIMP(META_CREATEBITMAP)
1047 #undef META_UNIMP
1049 default:
1050 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1051 return FALSE;
1053 return TRUE;
1056 /******************************************************************
1057 * SetMetaFileBitsEx (GDI32.@)
1059 * Create a metafile from raw data. No checking of the data is performed.
1060 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1062 * PARAMS
1063 * size [I] size of metafile, in bytes
1064 * lpData [I] pointer to metafile data
1066 * RETURNS
1067 * Success: Handle to metafile.
1068 * Failure: NULL.
1070 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1072 METAHEADER *mh = (METAHEADER *)lpData;
1074 if (size & 1) return 0;
1076 if (!size || mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
1077 mh->mtHeaderSize != sizeof(METAHEADER) / 2)
1079 SetLastError(ERROR_INVALID_DATA);
1080 return 0;
1083 mh = HeapAlloc( GetProcessHeap(), 0, size );
1084 if (!mh)
1086 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1087 return 0;
1090 memcpy(mh, lpData, size);
1091 mh->mtSize = size / 2;
1092 return MF_Create_HMETAFILE(mh);
1095 /*****************************************************************
1096 * GetMetaFileBitsEx (GDI32.@)
1098 * Get raw metafile data.
1100 * Copies the data from metafile _hmf_ into the buffer _buf_.
1102 * PARAMS
1103 * hmf [I] metafile
1104 * nSize [I] size of buf
1105 * buf [O] buffer to receive raw metafile data
1107 * RETURNS
1108 * If _buf_ is zero, returns size of buffer required. Otherwise,
1109 * returns number of bytes copied.
1111 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1113 METAHEADER *mh = MF_GetMetaHeader(hmf);
1114 UINT mfSize;
1116 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1117 if (!mh) return 0; /* FIXME: error code */
1118 if(mh->mtType == METAFILE_DISK)
1119 FIXME("Disk-based metafile?\n");
1120 mfSize = mh->mtSize * 2;
1121 if (!buf) {
1122 TRACE("returning size %d\n", mfSize);
1123 return mfSize;
1125 if(mfSize > nSize) mfSize = nSize;
1126 memmove(buf, mh, mfSize);
1127 return mfSize;
1130 /******************************************************************
1131 * GetWinMetaFileBits [GDI32.@]
1133 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1134 UINT cbBuffer, LPBYTE lpbBuffer,
1135 INT fnMapMode, HDC hdcRef)
1137 HDC hdcmf;
1138 HMETAFILE hmf;
1139 UINT ret;
1140 RECT rc;
1141 INT oldMapMode;
1143 GetClipBox(hdcRef, &rc);
1144 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1146 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1147 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1149 hdcmf = CreateMetaFileA(NULL);
1150 PlayEnhMetaFile(hdcmf, hemf, &rc);
1151 hmf = CloseMetaFile(hdcmf);
1152 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1153 DeleteMetaFile(hmf);
1155 SetMapMode(hdcRef, oldMapMode);
1157 return ret;
1160 /******************************************************************
1161 * MF_Play_MetaCreateRegion
1163 * Handles META_CREATEREGION for PlayMetaFileRecord().
1165 * The layout of the record looks something like this:
1167 * rdParm meaning
1168 * 0 Always 0?
1169 * 1 Always 6?
1170 * 2 Looks like a handle? - not constant
1171 * 3 0 or 1 ??
1172 * 4 Total number of bytes
1173 * 5 No. of separate bands = n [see below]
1174 * 6 Largest number of x co-ords in a band
1175 * 7-10 Bounding box x1 y1 x2 y2
1176 * 11-... n bands
1178 * Regions are divided into bands that are uniform in the
1179 * y-direction. Each band consists of pairs of on/off x-coords and is
1180 * written as
1181 * m y0 y1 x1 x2 x3 ... xm m
1182 * into successive rdParm[]s.
1184 * This is probably just a dump of the internal RGNOBJ?
1186 * HDMD - 18/12/97
1190 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1192 WORD band, pair;
1193 WORD *start, *end;
1194 INT16 y0, y1;
1195 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1197 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1198 band++, start = end + 1) {
1199 if(*start / 2 != (*start + 1) / 2) {
1200 WARN("Delimiter not even.\n");
1201 DeleteObject( hrgn2 );
1202 return FALSE;
1205 end = start + *start + 3;
1206 if(end > (WORD *)mr + mr->rdSize) {
1207 WARN("End points outside record.\n");
1208 DeleteObject( hrgn2 );
1209 return FALSE;
1212 if(*start != *end) {
1213 WARN("Mismatched delimiters.\n");
1214 DeleteObject( hrgn2 );
1215 return FALSE;
1218 y0 = *(INT16 *)(start + 1);
1219 y1 = *(INT16 *)(start + 2);
1220 for(pair = 0; pair < *start / 2; pair++) {
1221 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1222 *(INT16 *)(start + 4 + 2*pair), y1 );
1223 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1226 DeleteObject( hrgn2 );
1227 return TRUE;
1231 /******************************************************************
1232 * MF_Play_MetaExtTextOut
1234 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1237 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1239 INT *dx = NULL;
1240 int i;
1241 LPINT16 dxx;
1242 LPSTR sot;
1243 DWORD len;
1244 WORD s1;
1245 RECT rect;
1246 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1248 s1 = mr->rdParm[2]; /* String length */
1249 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1250 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1251 /* rec len without dx array */
1253 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1254 if (isrect)
1256 rect.left = (SHORT)mr->rdParm[4];
1257 rect.top = (SHORT)mr->rdParm[5];
1258 rect.right = (SHORT)mr->rdParm[6];
1259 rect.bottom = (SHORT)mr->rdParm[7];
1260 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1263 if (mr->rdSize == len / 2)
1264 dxx = NULL; /* determine if array present */
1265 else
1266 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1268 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1269 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1270 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1272 else {
1273 TRACE("%s len: %ld\n", sot, mr->rdSize);
1274 WARN("Please report: ExtTextOut len=%ld slen=%d rdSize=%ld opt=%04x\n",
1275 len, s1, mr->rdSize, mr->rdParm[3]);
1276 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1278 ExtTextOutA( hdc,
1279 (SHORT)mr->rdParm[1], /* X position */
1280 (SHORT)mr->rdParm[0], /* Y position */
1281 mr->rdParm[3], /* options */
1282 &rect, /* rectangle */
1283 sot, /* string */
1284 s1, dx); /* length, dx array */
1285 if (dx)
1287 TRACE("%s len: %ld dx0: %d\n", sot, mr->rdSize, dx[0]);
1288 HeapFree( GetProcessHeap(), 0, dx );
1290 return TRUE;