d3dx8: Implement D3DXMatrixRotationZ.
[wine/multimedia.git] / dlls / gdi32 / metafile.c
blob13fce773604fef232ef4f396e3a3d1046ae3bdc5
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <stdarg.h>
51 #include <string.h>
52 #include <fcntl.h>
54 #include "windef.h"
55 #include "winbase.h"
56 #include "wingdi.h"
57 #include "winreg.h"
58 #include "winternl.h"
59 #include "gdi_private.h"
60 #include "wine/debug.h"
62 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
64 #include "pshpack1.h"
65 typedef struct
67 DWORD dw1, dw2, dw3;
68 WORD w4;
69 CHAR filename[0x100];
70 } METAHEADERDISK;
71 #include "poppack.h"
73 typedef struct
75 GDIOBJHDR header;
76 METAHEADER *mh;
77 } METAFILEOBJ;
80 /******************************************************************
81 * MF_AddHandle
83 * Add a handle to an external handle table and return the index
85 static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
87 int i;
89 for (i = 0; i < htlen; i++)
91 if (*(ht->objectHandle + i) == 0)
93 *(ht->objectHandle + i) = hobj;
94 return i;
97 return -1;
101 /******************************************************************
102 * MF_Create_HMETATFILE
104 * Creates a (32 bit) HMETAFILE object from a METAHEADER
106 * HMETAFILEs are GDI objects.
108 HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
110 HMETAFILE hmf = 0;
111 METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
112 (HGDIOBJ *)&hmf, NULL );
113 if (metaObj)
115 metaObj->mh = mh;
116 GDI_ReleaseObj( hmf );
118 return hmf;
121 /******************************************************************
122 * MF_GetMetaHeader
124 * Returns ptr to METAHEADER associated with HMETAFILE
126 static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
128 METAHEADER *ret = NULL;
129 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
130 if (metaObj)
132 ret = metaObj->mh;
133 GDI_ReleaseObj( hmf );
135 return ret;
138 /******************************************************************
139 * convert_points
141 * Convert an array of POINT16 to an array of POINT.
142 * Result must be freed by caller.
144 static POINT *convert_points( UINT count, POINT16 *pt16 )
146 UINT i;
147 POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
148 if (ret)
150 for (i = 0; i < count; i++)
152 ret[i].x = pt16[i].x;
153 ret[i].y = pt16[i].y;
156 return ret;
159 /******************************************************************
160 * DeleteMetaFile (GDI32.@)
162 * Delete a memory-based metafile.
165 BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
167 METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
168 if (!metaObj) return FALSE;
169 HeapFree( GetProcessHeap(), 0, metaObj->mh );
170 GDI_FreeObject( hmf, metaObj );
171 return TRUE;
174 /******************************************************************
175 * MF_ReadMetaFile
177 * Returns a pointer to a memory based METAHEADER read in from file HFILE
180 METAHEADER *MF_ReadMetaFile(HANDLE hfile)
182 METAHEADER *mh;
183 DWORD BytesRead, size;
185 size = sizeof(METAHEADER);
186 mh = HeapAlloc( GetProcessHeap(), 0, size );
187 if(!mh) return NULL;
188 if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
189 BytesRead != size) {
190 HeapFree( GetProcessHeap(), 0, mh );
191 return NULL;
193 if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
194 mh->mtHeaderSize != size / 2)
196 HeapFree( GetProcessHeap(), 0, mh );
197 return NULL;
199 size = mh->mtSize * 2;
200 mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
201 if(!mh) return NULL;
202 size -= sizeof(METAHEADER);
203 if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
204 NULL) == 0 ||
205 BytesRead != size) {
206 HeapFree( GetProcessHeap(), 0, mh );
207 return NULL;
210 if (mh->mtType != METAFILE_MEMORY) {
211 WARN("Disk metafile had mtType = %04x\n", mh->mtType);
212 mh->mtType = METAFILE_MEMORY;
214 return mh;
217 /******************************************************************
218 * GetMetaFileA (GDI32.@)
220 * Read a metafile from a file. Returns handle to a memory-based metafile.
222 HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
224 METAHEADER *mh;
225 HANDLE hFile;
227 TRACE("%s\n", lpFilename);
229 if(!lpFilename)
230 return 0;
232 if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
233 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
234 return 0;
236 mh = MF_ReadMetaFile(hFile);
237 CloseHandle(hFile);
238 if(!mh) return 0;
239 return MF_Create_HMETAFILE( mh );
242 /******************************************************************
243 * GetMetaFileW (GDI32.@)
245 HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
247 METAHEADER *mh;
248 HANDLE hFile;
250 TRACE("%s\n", debugstr_w(lpFilename));
252 if(!lpFilename)
253 return 0;
255 if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
256 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
257 return 0;
259 mh = MF_ReadMetaFile(hFile);
260 CloseHandle(hFile);
261 if(!mh) return 0;
262 return MF_Create_HMETAFILE( mh );
266 /******************************************************************
267 * MF_LoadDiskBasedMetaFile
269 * Creates a new memory-based metafile from a disk-based one.
271 METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
273 METAHEADERDISK *mhd;
274 HANDLE hfile;
275 METAHEADER *mh2;
277 if(mh->mtType != METAFILE_DISK) {
278 ERR("Not a disk based metafile\n");
279 return NULL;
281 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
283 if((hfile = CreateFileA(mhd->filename, GENERIC_READ, FILE_SHARE_READ, NULL,
284 OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE) {
285 WARN("Can't open file of disk based metafile\n");
286 return NULL;
288 mh2 = MF_ReadMetaFile(hfile);
289 CloseHandle(hfile);
290 return mh2;
293 /******************************************************************
294 * MF_CreateMetaHeaderDisk
296 * Take a memory based METAHEADER and change it to a disk based METAHEADER
297 * assosiated with filename. Note: Trashes contents of old one.
299 METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
301 METAHEADERDISK *mhd;
303 mh = HeapReAlloc( GetProcessHeap(), 0, mh,
304 sizeof(METAHEADER) + sizeof(METAHEADERDISK));
305 mh->mtType = METAFILE_DISK;
306 mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
308 if( uni )
309 WideCharToMultiByte(CP_ACP, 0, filename, -1,
310 mhd->filename, sizeof mhd->filename, NULL, NULL);
311 else
312 lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
313 return mh;
316 /******************************************************************
317 * CopyMetaFileW (GDI32.@)
319 * Copies the metafile corresponding to hSrcMetaFile to either
320 * a disk file, if a filename is given, or to a new memory based
321 * metafile, if lpFileName is NULL.
323 * PARAMS
324 * hSrcMetaFile [I] handle of metafile to copy
325 * lpFilename [I] filename if copying to a file
327 * RETURNS
328 * Handle to metafile copy on success, NULL on failure.
330 * BUGS
331 * Copying to disk returns NULL even if successful.
333 HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
335 METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
336 METAHEADER *mh2 = NULL;
337 HANDLE hFile;
339 TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
341 if(!mh) return 0;
343 if(mh->mtType == METAFILE_DISK)
344 mh2 = MF_LoadDiskBasedMetaFile(mh);
345 else {
346 mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
347 memcpy( mh2, mh, mh->mtSize * 2 );
350 if(lpFilename) { /* disk based metafile */
351 DWORD w;
352 if((hFile = CreateFileW(lpFilename, GENERIC_WRITE, 0, NULL,
353 CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) {
354 HeapFree( GetProcessHeap(), 0, mh2 );
355 return 0;
357 WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
358 CloseHandle(hFile);
361 return MF_Create_HMETAFILE( mh2 );
365 /******************************************************************
366 * CopyMetaFileA (GDI32.@)
368 * See CopyMetaFileW.
370 HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
372 UNICODE_STRING lpFilenameW;
373 HMETAFILE ret = 0;
375 if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
376 else lpFilenameW.Buffer = NULL;
378 ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
379 if (lpFilenameW.Buffer)
380 RtlFreeUnicodeString(&lpFilenameW);
381 return ret;
384 /*******************************************************************
385 * MF_PlayMetaFile
387 * Helper for PlayMetaFile
389 BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
392 METARECORD *mr;
393 HANDLETABLE *ht;
394 unsigned int offset = 0;
395 WORD i;
396 HPEN hPen;
397 HBRUSH hBrush;
398 HFONT hFont;
399 BOOL loaded = FALSE;
401 if (!mh) return FALSE;
402 if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
403 mh = MF_LoadDiskBasedMetaFile(mh);
404 if(!mh) return FALSE;
405 loaded = TRUE;
408 /* save the current pen, brush and font */
409 hPen = GetCurrentObject(hdc, OBJ_PEN);
410 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
411 hFont = GetCurrentObject(hdc, OBJ_FONT);
413 /* create the handle table */
414 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
415 sizeof(HANDLETABLE) * mh->mtNoObjects);
416 if(!ht) return FALSE;
418 /* loop through metafile playing records */
419 offset = mh->mtHeaderSize * 2;
420 while (offset < mh->mtSize * 2)
422 mr = (METARECORD *)((char *)mh + offset);
423 TRACE("offset=%04x,size=%08x\n",
424 offset, mr->rdSize);
425 if (mr->rdSize < 3) { /* catch illegal record sizes */
426 TRACE("Entry got size %d at offset %d, total mf length is %d\n",
427 mr->rdSize,offset,mh->mtSize*2);
428 break;
430 offset += mr->rdSize * 2;
431 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
434 SelectObject(hdc, hBrush);
435 SelectObject(hdc, hPen);
436 SelectObject(hdc, hFont);
438 /* free objects in handle table */
439 for(i = 0; i < mh->mtNoObjects; i++)
440 if(*(ht->objectHandle + i) != 0)
441 DeleteObject(*(ht->objectHandle + i));
443 /* free handle table */
444 HeapFree( GetProcessHeap(), 0, ht );
445 if(loaded)
446 HeapFree( GetProcessHeap(), 0, mh );
447 return TRUE;
450 /******************************************************************
451 * PlayMetaFile (GDI32.@)
453 * Renders the metafile specified by hmf in the DC specified by
454 * hdc. Returns FALSE on failure, TRUE on success.
456 * PARAMS
457 * hdc [I] handle of DC to render in
458 * hmf [I] handle of metafile to render
460 * RETURNS
461 * Success: TRUE
462 * Failure: FALSE
464 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
466 METAHEADER *mh = MF_GetMetaHeader( hmf );
467 return MF_PlayMetaFile( hdc, mh );
470 /******************************************************************
471 * EnumMetaFile (GDI32.@)
473 * Loop through the metafile records in hmf, calling the user-specified
474 * function for each one, stopping when the user's function returns FALSE
475 * (which is considered to be failure)
476 * or when no records are left (which is considered to be success).
478 * RETURNS
479 * TRUE on success, FALSE on failure.
481 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
483 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
484 METARECORD *mr;
485 HANDLETABLE *ht;
486 BOOL result = TRUE;
487 int i;
488 unsigned int offset = 0;
489 HPEN hPen;
490 HBRUSH hBrush;
491 HFONT hFont;
493 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
494 if (!mh) return 0;
495 if(mh->mtType == METAFILE_DISK)
497 /* Create a memory-based copy */
498 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
499 mh = mhTemp;
502 /* save the current pen, brush and font */
503 hPen = GetCurrentObject(hdc, OBJ_PEN);
504 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
505 hFont = GetCurrentObject(hdc, OBJ_FONT);
507 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
508 sizeof(HANDLETABLE) * mh->mtNoObjects);
510 /* loop through metafile records */
511 offset = mh->mtHeaderSize * 2;
513 while (offset < (mh->mtSize * 2))
515 mr = (METARECORD *)((char *)mh + offset);
516 if(mr->rdFunction == META_EOF) {
517 TRACE("Got META_EOF so stopping\n");
518 break;
520 TRACE("Calling EnumFunc with record type %x\n",
521 mr->rdFunction);
522 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
524 result = FALSE;
525 break;
528 offset += (mr->rdSize * 2);
531 /* restore pen, brush and font */
532 SelectObject(hdc, hBrush);
533 SelectObject(hdc, hPen);
534 SelectObject(hdc, hFont);
536 /* free objects in handle table */
537 for(i = 0; i < mh->mtNoObjects; i++)
538 if(*(ht->objectHandle + i) != 0)
539 DeleteObject(*(ht->objectHandle + i));
541 /* free handle table */
542 HeapFree( GetProcessHeap(), 0, ht);
543 /* free a copy of metafile */
544 HeapFree( GetProcessHeap(), 0, mhTemp );
545 return result;
548 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
549 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
550 /******************************************************************
551 * PlayMetaFileRecord (GDI32.@)
553 * Render a single metafile record specified by *mr in the DC hdc, while
554 * using the handle table *ht, of length handles,
555 * to store metafile objects.
557 * BUGS
558 * The following metafile records are unimplemented:
560 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
561 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
562 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
564 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
566 short s1;
567 POINT *pt;
568 BITMAPINFOHEADER *infohdr;
570 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
572 switch (mr->rdFunction)
574 case META_EOF:
575 break;
577 case META_DELETEOBJECT:
578 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
579 *(ht->objectHandle + mr->rdParm[0]) = 0;
580 break;
582 case META_SETBKCOLOR:
583 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
584 break;
586 case META_SETBKMODE:
587 SetBkMode(hdc, mr->rdParm[0]);
588 break;
590 case META_SETMAPMODE:
591 SetMapMode(hdc, mr->rdParm[0]);
592 break;
594 case META_SETROP2:
595 SetROP2(hdc, mr->rdParm[0]);
596 break;
598 case META_SETRELABS:
599 SetRelAbs(hdc, mr->rdParm[0]);
600 break;
602 case META_SETPOLYFILLMODE:
603 SetPolyFillMode(hdc, mr->rdParm[0]);
604 break;
606 case META_SETSTRETCHBLTMODE:
607 SetStretchBltMode(hdc, mr->rdParm[0]);
608 break;
610 case META_SETTEXTCOLOR:
611 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
612 break;
614 case META_SETWINDOWORG:
615 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
616 break;
618 case META_SETWINDOWEXT:
619 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
620 break;
622 case META_SETVIEWPORTORG:
623 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
624 break;
626 case META_SETVIEWPORTEXT:
627 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
628 break;
630 case META_OFFSETWINDOWORG:
631 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
632 break;
634 case META_SCALEWINDOWEXT:
635 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
636 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
637 break;
639 case META_OFFSETVIEWPORTORG:
640 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
641 break;
643 case META_SCALEVIEWPORTEXT:
644 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
645 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
646 break;
648 case META_LINETO:
649 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
650 break;
652 case META_MOVETO:
653 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
654 break;
656 case META_EXCLUDECLIPRECT:
657 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
658 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
659 break;
661 case META_INTERSECTCLIPRECT:
662 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
663 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
664 break;
666 case META_ARC:
667 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
668 (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]);
671 break;
673 case META_ELLIPSE:
674 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
675 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
676 break;
678 case META_FLOODFILL:
679 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
680 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
681 break;
683 case META_PIE:
684 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
685 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
686 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
687 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
688 break;
690 case META_RECTANGLE:
691 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
692 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
693 break;
695 case META_ROUNDRECT:
696 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
697 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
698 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
699 break;
701 case META_PATBLT:
702 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
703 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
704 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
705 break;
707 case META_SAVEDC:
708 SaveDC(hdc);
709 break;
711 case META_SETPIXEL:
712 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
713 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
714 break;
716 case META_OFFSETCLIPRGN:
717 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
718 break;
720 case META_TEXTOUT:
721 s1 = mr->rdParm[0];
722 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
723 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
724 (char *)(mr->rdParm + 1), s1);
725 break;
727 case META_POLYGON:
728 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
730 Polygon(hdc, pt, mr->rdParm[0]);
731 HeapFree( GetProcessHeap(), 0, pt );
733 break;
735 case META_POLYPOLYGON:
737 UINT i, total;
738 SHORT *counts = (SHORT *)(mr->rdParm + 1);
740 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
741 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
742 if (pt)
744 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
745 if (cnt32)
747 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
748 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
749 HeapFree( GetProcessHeap(), 0, cnt32 );
752 HeapFree( GetProcessHeap(), 0, pt );
754 break;
756 case META_POLYLINE:
757 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
759 Polyline( hdc, pt, mr->rdParm[0] );
760 HeapFree( GetProcessHeap(), 0, pt );
762 break;
764 case META_RESTOREDC:
765 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
766 break;
768 case META_SELECTOBJECT:
769 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
770 break;
772 case META_CHORD:
773 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
774 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
775 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
776 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
777 break;
779 case META_CREATEPATTERNBRUSH:
780 switch (mr->rdParm[0])
782 case BS_PATTERN:
783 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
784 MF_AddHandle(ht, handles,
785 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
786 infohdr->biHeight,
787 infohdr->biPlanes,
788 infohdr->biBitCount,
789 (LPSTR)(mr->rdParm +
790 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
791 break;
793 case BS_DIBPATTERN:
794 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
795 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
796 break;
798 default:
799 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
800 mr->rdParm[0]);
801 break;
803 break;
805 case META_CREATEPENINDIRECT:
807 LOGPEN pen;
808 pen.lopnStyle = mr->rdParm[0];
809 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
810 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
811 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
812 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
814 break;
816 case META_CREATEFONTINDIRECT:
818 LOGFONTA font;
819 font.lfHeight = (SHORT)mr->rdParm[0];
820 font.lfWidth = (SHORT)mr->rdParm[1];
821 font.lfEscapement = (SHORT)mr->rdParm[2];
822 font.lfOrientation = (SHORT)mr->rdParm[3];
823 font.lfWeight = (SHORT)mr->rdParm[4];
824 font.lfItalic = LOBYTE(mr->rdParm[5]);
825 font.lfUnderline = HIBYTE(mr->rdParm[5]);
826 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
827 font.lfCharSet = HIBYTE(mr->rdParm[6]);
828 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
829 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
830 font.lfQuality = LOBYTE(mr->rdParm[8]);
831 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
832 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
833 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
835 break;
837 case META_CREATEBRUSHINDIRECT:
839 LOGBRUSH brush;
840 brush.lbStyle = mr->rdParm[0];
841 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
842 brush.lbHatch = mr->rdParm[3];
843 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
845 break;
847 case META_CREATEPALETTE:
848 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
849 break;
851 case META_SETTEXTALIGN:
852 SetTextAlign(hdc, mr->rdParm[0]);
853 break;
855 case META_SELECTPALETTE:
856 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
857 break;
859 case META_SETMAPPERFLAGS:
860 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
861 break;
863 case META_REALIZEPALETTE:
864 GDIRealizePalette(hdc);
865 break;
867 case META_ESCAPE:
868 switch (mr->rdParm[0]) {
869 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
870 case GETPHYSPAGESIZE:
871 case GETPRINTINGOFFSET:
872 return FALSE;
873 case SETABORTPROC:
874 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
875 return FALSE;
877 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
878 break;
880 case META_EXTTEXTOUT:
881 MF_Play_MetaExtTextOut( hdc, mr );
882 break;
884 case META_STRETCHDIB:
886 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
887 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
888 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
889 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
890 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
891 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
893 break;
895 case META_DIBSTRETCHBLT:
897 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
898 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
899 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
900 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
901 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
902 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
904 break;
906 case META_STRETCHBLT:
908 HDC hdcSrc = CreateCompatibleDC(hdc);
909 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
910 mr->rdParm[11], /*Height*/
911 mr->rdParm[13], /*Planes*/
912 mr->rdParm[14], /*BitsPixel*/
913 (LPSTR)&mr->rdParm[15]); /*bits*/
914 SelectObject(hdcSrc,hbitmap);
915 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
916 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
917 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
918 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
919 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
920 DeleteDC(hdcSrc);
922 break;
924 case META_BITBLT:
926 HDC hdcSrc = CreateCompatibleDC(hdc);
927 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
928 mr->rdParm[8]/*Height*/,
929 mr->rdParm[10]/*Planes*/,
930 mr->rdParm[11]/*BitsPixel*/,
931 (LPSTR)&mr->rdParm[12]/*bits*/);
932 SelectObject(hdcSrc,hbitmap);
933 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
934 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
935 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
936 MAKELONG(0,mr->rdParm[0]));
937 DeleteDC(hdcSrc);
939 break;
941 case META_CREATEREGION:
943 HRGN hrgn = CreateRectRgn(0,0,0,0);
945 MF_Play_MetaCreateRegion(mr, hrgn);
946 MF_AddHandle(ht, handles, hrgn);
948 break;
950 case META_FILLREGION:
951 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
952 *(ht->objectHandle + mr->rdParm[0]));
953 break;
955 case META_FRAMEREGION:
956 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
957 *(ht->objectHandle + mr->rdParm[2]),
958 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
959 break;
961 case META_INVERTREGION:
962 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
963 break;
965 case META_PAINTREGION:
966 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
967 break;
969 case META_SELECTCLIPREGION:
971 HRGN hrgn = 0;
973 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
974 SelectClipRgn(hdc, hrgn);
976 break;
978 case META_DIBCREATEPATTERNBRUSH:
979 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
980 but there's no difference */
981 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
982 break;
984 case META_DIBBITBLT:
985 /* In practice I've found that there are two layouts for
986 META_DIBBITBLT, one (the first here) is the usual one when a src
987 dc is actually passed to it, the second occurs when the src dc is
988 passed in as NULL to the creating BitBlt. As the second case has
989 no dib, a size check will suffice to distinguish.
991 Caolan.McNamara@ul.ie */
993 if (mr->rdSize > 12) {
994 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
995 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
997 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
998 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
999 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1000 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1002 else /* equivalent to a PatBlt */
1003 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1004 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1005 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1006 break;
1008 case META_SETTEXTCHAREXTRA:
1009 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1010 break;
1012 case META_SETTEXTJUSTIFICATION:
1013 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1014 break;
1016 case META_EXTFLOODFILL:
1017 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1018 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1019 mr->rdParm[0]);
1020 break;
1022 case META_SETDIBTODEV:
1024 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1025 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1026 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1027 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1028 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1029 mr->rdParm[2], mr->rdParm[1], bits, info,
1030 mr->rdParm[0]);
1031 break;
1034 #define META_UNIMP(x) case x: \
1035 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1036 break;
1037 META_UNIMP(META_DRAWTEXT)
1038 META_UNIMP(META_ANIMATEPALETTE)
1039 META_UNIMP(META_SETPALENTRIES)
1040 META_UNIMP(META_RESIZEPALETTE)
1041 META_UNIMP(META_RESETDC)
1042 META_UNIMP(META_STARTDOC)
1043 META_UNIMP(META_STARTPAGE)
1044 META_UNIMP(META_ENDPAGE)
1045 META_UNIMP(META_ABORTDOC)
1046 META_UNIMP(META_ENDDOC)
1047 META_UNIMP(META_CREATEBRUSH)
1048 META_UNIMP(META_CREATEBITMAPINDIRECT)
1049 META_UNIMP(META_CREATEBITMAP)
1050 #undef META_UNIMP
1052 default:
1053 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1054 return FALSE;
1056 return TRUE;
1059 /******************************************************************
1060 * SetMetaFileBitsEx (GDI32.@)
1062 * Create a metafile from raw data. No checking of the data is performed.
1063 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1065 * PARAMS
1066 * size [I] size of metafile, in bytes
1067 * lpData [I] pointer to metafile data
1069 * RETURNS
1070 * Success: Handle to metafile.
1071 * Failure: NULL.
1073 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1075 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1076 METAHEADER *mh_out;
1078 if (size & 1) return 0;
1080 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1081 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1083 SetLastError(ERROR_INVALID_DATA);
1084 return 0;
1087 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1088 if (!mh_out)
1090 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1091 return 0;
1094 memcpy(mh_out, mh_in, size);
1095 mh_out->mtSize = size / 2;
1096 return MF_Create_HMETAFILE(mh_out);
1099 /*****************************************************************
1100 * GetMetaFileBitsEx (GDI32.@)
1102 * Get raw metafile data.
1104 * Copies the data from metafile _hmf_ into the buffer _buf_.
1106 * PARAMS
1107 * hmf [I] metafile
1108 * nSize [I] size of buf
1109 * buf [O] buffer to receive raw metafile data
1111 * RETURNS
1112 * If _buf_ is zero, returns size of buffer required. Otherwise,
1113 * returns number of bytes copied.
1115 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1117 METAHEADER *mh = MF_GetMetaHeader(hmf);
1118 UINT mfSize;
1120 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1121 if (!mh) return 0; /* FIXME: error code */
1122 if(mh->mtType == METAFILE_DISK)
1123 FIXME("Disk-based metafile?\n");
1124 mfSize = mh->mtSize * 2;
1125 if (!buf) {
1126 TRACE("returning size %d\n", mfSize);
1127 return mfSize;
1129 if(mfSize > nSize) mfSize = nSize;
1130 memmove(buf, mh, mfSize);
1131 return mfSize;
1134 /******************************************************************
1135 * GetWinMetaFileBits [GDI32.@]
1137 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1138 UINT cbBuffer, LPBYTE lpbBuffer,
1139 INT fnMapMode, HDC hdcRef)
1141 HDC hdcmf;
1142 HMETAFILE hmf;
1143 UINT ret;
1144 RECT rc;
1145 INT oldMapMode;
1147 GetClipBox(hdcRef, &rc);
1148 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1150 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1151 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1153 hdcmf = CreateMetaFileA(NULL);
1154 PlayEnhMetaFile(hdcmf, hemf, &rc);
1155 hmf = CloseMetaFile(hdcmf);
1156 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1157 DeleteMetaFile(hmf);
1159 SetMapMode(hdcRef, oldMapMode);
1161 return ret;
1164 /******************************************************************
1165 * MF_Play_MetaCreateRegion
1167 * Handles META_CREATEREGION for PlayMetaFileRecord().
1169 * The layout of the record looks something like this:
1171 * rdParm meaning
1172 * 0 Always 0?
1173 * 1 Always 6?
1174 * 2 Looks like a handle? - not constant
1175 * 3 0 or 1 ??
1176 * 4 Total number of bytes
1177 * 5 No. of separate bands = n [see below]
1178 * 6 Largest number of x co-ords in a band
1179 * 7-10 Bounding box x1 y1 x2 y2
1180 * 11-... n bands
1182 * Regions are divided into bands that are uniform in the
1183 * y-direction. Each band consists of pairs of on/off x-coords and is
1184 * written as
1185 * m y0 y1 x1 x2 x3 ... xm m
1186 * into successive rdParm[]s.
1188 * This is probably just a dump of the internal RGNOBJ?
1190 * HDMD - 18/12/97
1194 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1196 WORD band, pair;
1197 WORD *start, *end;
1198 INT16 y0, y1;
1199 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1201 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1202 band++, start = end + 1) {
1203 if(*start / 2 != (*start + 1) / 2) {
1204 WARN("Delimiter not even.\n");
1205 DeleteObject( hrgn2 );
1206 return FALSE;
1209 end = start + *start + 3;
1210 if(end > (WORD *)mr + mr->rdSize) {
1211 WARN("End points outside record.\n");
1212 DeleteObject( hrgn2 );
1213 return FALSE;
1216 if(*start != *end) {
1217 WARN("Mismatched delimiters.\n");
1218 DeleteObject( hrgn2 );
1219 return FALSE;
1222 y0 = *(INT16 *)(start + 1);
1223 y1 = *(INT16 *)(start + 2);
1224 for(pair = 0; pair < *start / 2; pair++) {
1225 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1226 *(INT16 *)(start + 4 + 2*pair), y1 );
1227 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1230 DeleteObject( hrgn2 );
1231 return TRUE;
1235 /******************************************************************
1236 * MF_Play_MetaExtTextOut
1238 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1241 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1243 INT *dx = NULL;
1244 int i;
1245 LPINT16 dxx;
1246 LPSTR sot;
1247 DWORD len;
1248 WORD s1;
1249 RECT rect;
1250 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1252 s1 = mr->rdParm[2]; /* String length */
1253 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1254 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1255 /* rec len without dx array */
1257 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1258 if (isrect)
1260 rect.left = (SHORT)mr->rdParm[4];
1261 rect.top = (SHORT)mr->rdParm[5];
1262 rect.right = (SHORT)mr->rdParm[6];
1263 rect.bottom = (SHORT)mr->rdParm[7];
1264 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1267 if (mr->rdSize == len / 2)
1268 dxx = NULL; /* determine if array present */
1269 else
1270 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1272 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1273 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1274 if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
1276 else {
1277 TRACE("%s len: %d\n", sot, mr->rdSize);
1278 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1279 len, s1, mr->rdSize, mr->rdParm[3]);
1280 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1282 ExtTextOutA( hdc,
1283 (SHORT)mr->rdParm[1], /* X position */
1284 (SHORT)mr->rdParm[0], /* Y position */
1285 mr->rdParm[3], /* options */
1286 &rect, /* rectangle */
1287 sot, /* string */
1288 s1, dx); /* length, dx array */
1289 if (dx)
1291 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1292 HeapFree( GetProcessHeap(), 0, dx );
1294 return TRUE;