push f2fb4b43e6a5ad960b5745b9c70e0a8fefaca935
[wine/hacks.git] / dlls / gdi32 / metafile.c
blobd04a03d68c22fd91555877fd1d9f646db13b1b86
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;
431 offset += mr->rdSize * 2;
432 if (mr->rdFunction == META_EOF) {
433 TRACE("Got META_EOF so stopping\n");
434 break;
436 PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
439 SelectObject(hdc, hBrush);
440 SelectObject(hdc, hPen);
441 SelectObject(hdc, hFont);
443 /* free objects in handle table */
444 for(i = 0; i < mh->mtNoObjects; i++)
445 if(*(ht->objectHandle + i) != 0)
446 DeleteObject(*(ht->objectHandle + i));
448 /* free handle table */
449 HeapFree( GetProcessHeap(), 0, ht );
450 if(loaded)
451 HeapFree( GetProcessHeap(), 0, mh );
452 return TRUE;
455 /******************************************************************
456 * PlayMetaFile (GDI32.@)
458 * Renders the metafile specified by hmf in the DC specified by
459 * hdc. Returns FALSE on failure, TRUE on success.
461 * PARAMS
462 * hdc [I] handle of DC to render in
463 * hmf [I] handle of metafile to render
465 * RETURNS
466 * Success: TRUE
467 * Failure: FALSE
469 BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
471 METAHEADER *mh = MF_GetMetaHeader( hmf );
472 return MF_PlayMetaFile( hdc, mh );
475 /******************************************************************
476 * EnumMetaFile (GDI32.@)
478 * Loop through the metafile records in hmf, calling the user-specified
479 * function for each one, stopping when the user's function returns FALSE
480 * (which is considered to be failure)
481 * or when no records are left (which is considered to be success).
483 * RETURNS
484 * TRUE on success, FALSE on failure.
486 BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
488 METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
489 METARECORD *mr;
490 HANDLETABLE *ht;
491 BOOL result = TRUE;
492 int i;
493 unsigned int offset = 0;
494 HPEN hPen;
495 HBRUSH hBrush;
496 HFONT hFont;
498 TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
499 if (!mh) return 0;
500 if(mh->mtType == METAFILE_DISK)
502 /* Create a memory-based copy */
503 if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
504 mh = mhTemp;
507 /* save the current pen, brush and font */
508 hPen = GetCurrentObject(hdc, OBJ_PEN);
509 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
510 hFont = GetCurrentObject(hdc, OBJ_FONT);
512 ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
513 sizeof(HANDLETABLE) * mh->mtNoObjects);
515 /* loop through metafile records */
516 offset = mh->mtHeaderSize * 2;
518 while (offset < (mh->mtSize * 2))
520 mr = (METARECORD *)((char *)mh + offset);
521 if(mr->rdFunction == META_EOF) {
522 TRACE("Got META_EOF so stopping\n");
523 break;
525 TRACE("Calling EnumFunc with record type %x\n",
526 mr->rdFunction);
527 if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
529 result = FALSE;
530 break;
533 offset += (mr->rdSize * 2);
536 /* restore pen, brush and font */
537 SelectObject(hdc, hBrush);
538 SelectObject(hdc, hPen);
539 SelectObject(hdc, hFont);
541 /* free objects in handle table */
542 for(i = 0; i < mh->mtNoObjects; i++)
543 if(*(ht->objectHandle + i) != 0)
544 DeleteObject(*(ht->objectHandle + i));
546 /* free handle table */
547 HeapFree( GetProcessHeap(), 0, ht);
548 /* free a copy of metafile */
549 HeapFree( GetProcessHeap(), 0, mhTemp );
550 return result;
553 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
554 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
555 /******************************************************************
556 * PlayMetaFileRecord (GDI32.@)
558 * Render a single metafile record specified by *mr in the DC hdc, while
559 * using the handle table *ht, of length handles,
560 * to store metafile objects.
562 * BUGS
563 * The following metafile records are unimplemented:
565 * DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
566 * RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
567 * ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
569 BOOL WINAPI PlayMetaFileRecord( HDC hdc, HANDLETABLE *ht, METARECORD *mr, UINT handles )
571 short s1;
572 POINT *pt;
573 BITMAPINFOHEADER *infohdr;
575 TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
577 switch (mr->rdFunction)
579 case META_EOF:
580 break;
582 case META_DELETEOBJECT:
583 DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
584 *(ht->objectHandle + mr->rdParm[0]) = 0;
585 break;
587 case META_SETBKCOLOR:
588 SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
589 break;
591 case META_SETBKMODE:
592 SetBkMode(hdc, mr->rdParm[0]);
593 break;
595 case META_SETMAPMODE:
596 SetMapMode(hdc, mr->rdParm[0]);
597 break;
599 case META_SETROP2:
600 SetROP2(hdc, mr->rdParm[0]);
601 break;
603 case META_SETRELABS:
604 SetRelAbs(hdc, mr->rdParm[0]);
605 break;
607 case META_SETPOLYFILLMODE:
608 SetPolyFillMode(hdc, mr->rdParm[0]);
609 break;
611 case META_SETSTRETCHBLTMODE:
612 SetStretchBltMode(hdc, mr->rdParm[0]);
613 break;
615 case META_SETTEXTCOLOR:
616 SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
617 break;
619 case META_SETWINDOWORG:
620 SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
621 break;
623 case META_SETWINDOWEXT:
624 SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
625 break;
627 case META_SETVIEWPORTORG:
628 SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
629 break;
631 case META_SETVIEWPORTEXT:
632 SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
633 break;
635 case META_OFFSETWINDOWORG:
636 OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
637 break;
639 case META_SCALEWINDOWEXT:
640 ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
641 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
642 break;
644 case META_OFFSETVIEWPORTORG:
645 OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
646 break;
648 case META_SCALEVIEWPORTEXT:
649 ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
650 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
651 break;
653 case META_LINETO:
654 LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
655 break;
657 case META_MOVETO:
658 MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
659 break;
661 case META_EXCLUDECLIPRECT:
662 ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
663 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
664 break;
666 case META_INTERSECTCLIPRECT:
667 IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
668 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
669 break;
671 case META_ARC:
672 Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
673 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
674 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
675 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
676 break;
678 case META_ELLIPSE:
679 Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
680 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
681 break;
683 case META_FLOODFILL:
684 FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
685 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
686 break;
688 case META_PIE:
689 Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
690 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
691 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
692 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
693 break;
695 case META_RECTANGLE:
696 Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
697 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
698 break;
700 case META_ROUNDRECT:
701 RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
702 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
703 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
704 break;
706 case META_PATBLT:
707 PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
708 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
709 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
710 break;
712 case META_SAVEDC:
713 SaveDC(hdc);
714 break;
716 case META_SETPIXEL:
717 SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
718 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
719 break;
721 case META_OFFSETCLIPRGN:
722 OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
723 break;
725 case META_TEXTOUT:
726 s1 = mr->rdParm[0];
727 TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
728 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
729 (char *)(mr->rdParm + 1), s1);
730 break;
732 case META_POLYGON:
733 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
735 Polygon(hdc, pt, mr->rdParm[0]);
736 HeapFree( GetProcessHeap(), 0, pt );
738 break;
740 case META_POLYPOLYGON:
742 UINT i, total;
743 SHORT *counts = (SHORT *)(mr->rdParm + 1);
745 for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
746 pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
747 if (pt)
749 INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
750 if (cnt32)
752 for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
753 PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
754 HeapFree( GetProcessHeap(), 0, cnt32 );
757 HeapFree( GetProcessHeap(), 0, pt );
759 break;
761 case META_POLYLINE:
762 if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
764 Polyline( hdc, pt, mr->rdParm[0] );
765 HeapFree( GetProcessHeap(), 0, pt );
767 break;
769 case META_RESTOREDC:
770 RestoreDC(hdc, (SHORT)mr->rdParm[0]);
771 break;
773 case META_SELECTOBJECT:
774 SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
775 break;
777 case META_CHORD:
778 Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
779 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
780 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
781 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
782 break;
784 case META_CREATEPATTERNBRUSH:
785 switch (mr->rdParm[0])
787 case BS_PATTERN:
788 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
789 MF_AddHandle(ht, handles,
790 CreatePatternBrush(CreateBitmap(infohdr->biWidth,
791 infohdr->biHeight,
792 infohdr->biPlanes,
793 infohdr->biBitCount,
794 (LPSTR)(mr->rdParm +
795 (sizeof(BITMAPINFOHEADER) / 2) + 4))));
796 break;
798 case BS_DIBPATTERN:
799 infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
800 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
801 break;
803 default:
804 ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
805 mr->rdParm[0]);
806 break;
808 break;
810 case META_CREATEPENINDIRECT:
812 LOGPEN pen;
813 pen.lopnStyle = mr->rdParm[0];
814 pen.lopnWidth.x = (SHORT)mr->rdParm[1];
815 pen.lopnWidth.y = (SHORT)mr->rdParm[2];
816 pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
817 MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
819 break;
821 case META_CREATEFONTINDIRECT:
823 LOGFONTA font;
824 font.lfHeight = (SHORT)mr->rdParm[0];
825 font.lfWidth = (SHORT)mr->rdParm[1];
826 font.lfEscapement = (SHORT)mr->rdParm[2];
827 font.lfOrientation = (SHORT)mr->rdParm[3];
828 font.lfWeight = (SHORT)mr->rdParm[4];
829 font.lfItalic = LOBYTE(mr->rdParm[5]);
830 font.lfUnderline = HIBYTE(mr->rdParm[5]);
831 font.lfStrikeOut = LOBYTE(mr->rdParm[6]);
832 font.lfCharSet = HIBYTE(mr->rdParm[6]);
833 font.lfOutPrecision = LOBYTE(mr->rdParm[7]);
834 font.lfClipPrecision = HIBYTE(mr->rdParm[7]);
835 font.lfQuality = LOBYTE(mr->rdParm[8]);
836 font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
837 memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
838 MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
840 break;
842 case META_CREATEBRUSHINDIRECT:
844 LOGBRUSH brush;
845 brush.lbStyle = mr->rdParm[0];
846 brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
847 brush.lbHatch = mr->rdParm[3];
848 MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
850 break;
852 case META_CREATEPALETTE:
853 MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
854 break;
856 case META_SETTEXTALIGN:
857 SetTextAlign(hdc, mr->rdParm[0]);
858 break;
860 case META_SELECTPALETTE:
861 GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
862 break;
864 case META_SETMAPPERFLAGS:
865 SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
866 break;
868 case META_REALIZEPALETTE:
869 GDIRealizePalette(hdc);
870 break;
872 case META_ESCAPE:
873 switch (mr->rdParm[0]) {
874 case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
875 case GETPHYSPAGESIZE:
876 case GETPRINTINGOFFSET:
877 return FALSE;
878 case SETABORTPROC:
879 FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
880 return FALSE;
882 Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
883 break;
885 case META_EXTTEXTOUT:
886 MF_Play_MetaExtTextOut( hdc, mr );
887 break;
889 case META_STRETCHDIB:
891 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
892 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
893 StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
894 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
895 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
896 mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
898 break;
900 case META_DIBSTRETCHBLT:
902 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
903 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
904 StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
905 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
906 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
907 DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
909 break;
911 case META_STRETCHBLT:
913 HDC hdcSrc = CreateCompatibleDC(hdc);
914 HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
915 mr->rdParm[11], /*Height*/
916 mr->rdParm[13], /*Planes*/
917 mr->rdParm[14], /*BitsPixel*/
918 (LPSTR)&mr->rdParm[15]); /*bits*/
919 SelectObject(hdcSrc,hbitmap);
920 StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
921 (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
922 hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
923 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
924 MAKELONG(mr->rdParm[0],mr->rdParm[1]));
925 DeleteDC(hdcSrc);
927 break;
929 case META_BITBLT:
931 HDC hdcSrc = CreateCompatibleDC(hdc);
932 HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
933 mr->rdParm[8]/*Height*/,
934 mr->rdParm[10]/*Planes*/,
935 mr->rdParm[11]/*BitsPixel*/,
936 (LPSTR)&mr->rdParm[12]/*bits*/);
937 SelectObject(hdcSrc,hbitmap);
938 BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
939 (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
940 hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
941 MAKELONG(0,mr->rdParm[0]));
942 DeleteDC(hdcSrc);
944 break;
946 case META_CREATEREGION:
948 HRGN hrgn = CreateRectRgn(0,0,0,0);
950 MF_Play_MetaCreateRegion(mr, hrgn);
951 MF_AddHandle(ht, handles, hrgn);
953 break;
955 case META_FILLREGION:
956 FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
957 *(ht->objectHandle + mr->rdParm[0]));
958 break;
960 case META_FRAMEREGION:
961 FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
962 *(ht->objectHandle + mr->rdParm[2]),
963 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
964 break;
966 case META_INVERTREGION:
967 InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
968 break;
970 case META_PAINTREGION:
971 PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
972 break;
974 case META_SELECTCLIPREGION:
976 HRGN hrgn = 0;
978 if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
979 SelectClipRgn(hdc, hrgn);
981 break;
983 case META_DIBCREATEPATTERNBRUSH:
984 /* mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
985 but there's no difference */
986 MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
987 break;
989 case META_DIBBITBLT:
990 /* In practice I've found that there are two layouts for
991 META_DIBBITBLT, one (the first here) is the usual one when a src
992 dc is actually passed to it, the second occurs when the src dc is
993 passed in as NULL to the creating BitBlt. As the second case has
994 no dib, a size check will suffice to distinguish.
996 Caolan.McNamara@ul.ie */
998 if (mr->rdSize > 12) {
999 LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
1000 LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);
1002 StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1003 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
1004 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
1005 DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1007 else /* equivalent to a PatBlt */
1008 PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1009 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1010 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
1011 break;
1013 case META_SETTEXTCHAREXTRA:
1014 SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
1015 break;
1017 case META_SETTEXTJUSTIFICATION:
1018 SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
1019 break;
1021 case META_EXTFLOODFILL:
1022 ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1023 MAKELONG(mr->rdParm[1], mr->rdParm[2]),
1024 mr->rdParm[0]);
1025 break;
1027 case META_SETDIBTODEV:
1029 BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
1030 char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
1031 SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
1032 (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
1033 (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
1034 mr->rdParm[2], mr->rdParm[1], bits, info,
1035 mr->rdParm[0]);
1036 break;
1039 #define META_UNIMP(x) case x: \
1040 FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1041 break;
1042 META_UNIMP(META_DRAWTEXT)
1043 META_UNIMP(META_ANIMATEPALETTE)
1044 META_UNIMP(META_SETPALENTRIES)
1045 META_UNIMP(META_RESIZEPALETTE)
1046 META_UNIMP(META_RESETDC)
1047 META_UNIMP(META_STARTDOC)
1048 META_UNIMP(META_STARTPAGE)
1049 META_UNIMP(META_ENDPAGE)
1050 META_UNIMP(META_ABORTDOC)
1051 META_UNIMP(META_ENDDOC)
1052 META_UNIMP(META_CREATEBRUSH)
1053 META_UNIMP(META_CREATEBITMAPINDIRECT)
1054 META_UNIMP(META_CREATEBITMAP)
1055 #undef META_UNIMP
1057 default:
1058 WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
1059 return FALSE;
1061 return TRUE;
1064 /******************************************************************
1065 * SetMetaFileBitsEx (GDI32.@)
1067 * Create a metafile from raw data. No checking of the data is performed.
1068 * Use GetMetaFileBitsEx() to get raw data from a metafile.
1070 * PARAMS
1071 * size [I] size of metafile, in bytes
1072 * lpData [I] pointer to metafile data
1074 * RETURNS
1075 * Success: Handle to metafile.
1076 * Failure: NULL.
1078 HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
1080 const METAHEADER *mh_in = (const METAHEADER *)lpData;
1081 METAHEADER *mh_out;
1083 if (size & 1) return 0;
1085 if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
1086 mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1088 SetLastError(ERROR_INVALID_DATA);
1089 return 0;
1092 mh_out = HeapAlloc( GetProcessHeap(), 0, size );
1093 if (!mh_out)
1095 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1096 return 0;
1099 memcpy(mh_out, mh_in, size);
1100 mh_out->mtSize = size / 2;
1101 return MF_Create_HMETAFILE(mh_out);
1104 /*****************************************************************
1105 * GetMetaFileBitsEx (GDI32.@)
1107 * Get raw metafile data.
1109 * Copies the data from metafile _hmf_ into the buffer _buf_.
1111 * PARAMS
1112 * hmf [I] metafile
1113 * nSize [I] size of buf
1114 * buf [O] buffer to receive raw metafile data
1116 * RETURNS
1117 * If _buf_ is zero, returns size of buffer required. Otherwise,
1118 * returns number of bytes copied.
1120 UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
1122 METAHEADER *mh = MF_GetMetaHeader(hmf);
1123 UINT mfSize;
1125 TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1126 if (!mh) return 0; /* FIXME: error code */
1127 if(mh->mtType == METAFILE_DISK)
1128 FIXME("Disk-based metafile?\n");
1129 mfSize = mh->mtSize * 2;
1130 if (!buf) {
1131 TRACE("returning size %d\n", mfSize);
1132 return mfSize;
1134 if(mfSize > nSize) mfSize = nSize;
1135 memmove(buf, mh, mfSize);
1136 return mfSize;
1139 /******************************************************************
1140 * GetWinMetaFileBits [GDI32.@]
1142 UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
1143 UINT cbBuffer, LPBYTE lpbBuffer,
1144 INT fnMapMode, HDC hdcRef)
1146 HDC hdcmf;
1147 HMETAFILE hmf;
1148 UINT ret;
1149 RECT rc;
1150 INT oldMapMode;
1152 GetClipBox(hdcRef, &rc);
1153 oldMapMode = SetMapMode(hdcRef, fnMapMode);
1155 TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
1156 fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1158 hdcmf = CreateMetaFileA(NULL);
1159 PlayEnhMetaFile(hdcmf, hemf, &rc);
1160 hmf = CloseMetaFile(hdcmf);
1161 ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
1162 DeleteMetaFile(hmf);
1164 SetMapMode(hdcRef, oldMapMode);
1166 return ret;
1169 /******************************************************************
1170 * MF_Play_MetaCreateRegion
1172 * Handles META_CREATEREGION for PlayMetaFileRecord().
1174 * The layout of the record looks something like this:
1176 * rdParm meaning
1177 * 0 Always 0?
1178 * 1 Always 6?
1179 * 2 Looks like a handle? - not constant
1180 * 3 0 or 1 ??
1181 * 4 Total number of bytes
1182 * 5 No. of separate bands = n [see below]
1183 * 6 Largest number of x co-ords in a band
1184 * 7-10 Bounding box x1 y1 x2 y2
1185 * 11-... n bands
1187 * Regions are divided into bands that are uniform in the
1188 * y-direction. Each band consists of pairs of on/off x-coords and is
1189 * written as
1190 * m y0 y1 x1 x2 x3 ... xm m
1191 * into successive rdParm[]s.
1193 * This is probably just a dump of the internal RGNOBJ?
1195 * HDMD - 18/12/97
1199 static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
1201 WORD band, pair;
1202 WORD *start, *end;
1203 INT16 y0, y1;
1204 HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
1206 for(band = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
1207 band++, start = end + 1) {
1208 if(*start / 2 != (*start + 1) / 2) {
1209 WARN("Delimiter not even.\n");
1210 DeleteObject( hrgn2 );
1211 return FALSE;
1214 end = start + *start + 3;
1215 if(end > (WORD *)mr + mr->rdSize) {
1216 WARN("End points outside record.\n");
1217 DeleteObject( hrgn2 );
1218 return FALSE;
1221 if(*start != *end) {
1222 WARN("Mismatched delimiters.\n");
1223 DeleteObject( hrgn2 );
1224 return FALSE;
1227 y0 = *(INT16 *)(start + 1);
1228 y1 = *(INT16 *)(start + 2);
1229 for(pair = 0; pair < *start / 2; pair++) {
1230 SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
1231 *(INT16 *)(start + 4 + 2*pair), y1 );
1232 CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
1235 DeleteObject( hrgn2 );
1236 return TRUE;
1240 /******************************************************************
1241 * MF_Play_MetaExtTextOut
1243 * Handles META_EXTTEXTOUT for PlayMetaFileRecord().
1246 static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1248 INT *dx = NULL;
1249 int i;
1250 LPINT16 dxx;
1251 LPSTR sot;
1252 DWORD len;
1253 WORD s1;
1254 RECT rect;
1255 BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1257 s1 = mr->rdParm[2]; /* String length */
1258 len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1259 + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1260 /* rec len without dx array */
1262 sot = (LPSTR)&mr->rdParm[4]; /* start_of_text */
1263 if (isrect)
1265 rect.left = (SHORT)mr->rdParm[4];
1266 rect.top = (SHORT)mr->rdParm[5];
1267 rect.right = (SHORT)mr->rdParm[6];
1268 rect.bottom = (SHORT)mr->rdParm[7];
1269 sot += sizeof(RECT16); /* there is a rectangle, so add offset */
1272 if (mr->rdSize == len / 2)
1273 dxx = NULL; /* determine if array present */
1274 else
1275 if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1277 dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
1278 dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
1279 if (dx) for (i = 0; i < s1; i++) dx[i] = dxx[i];
1281 else {
1282 TRACE("%s len: %d\n", sot, mr->rdSize);
1283 WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1284 len, s1, mr->rdSize, mr->rdParm[3]);
1285 dxx = NULL; /* should't happen -- but if, we continue with NULL */
1287 ExtTextOutA( hdc,
1288 (SHORT)mr->rdParm[1], /* X position */
1289 (SHORT)mr->rdParm[0], /* Y position */
1290 mr->rdParm[3], /* options */
1291 &rect, /* rectangle */
1292 sot, /* string */
1293 s1, dx); /* length, dx array */
1294 if (dx)
1296 TRACE("%s len: %d dx0: %d\n", sot, mr->rdSize, dx[0]);
1297 HeapFree( GetProcessHeap(), 0, dx );
1299 return TRUE;