metafile.c 39 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3 4
/*
 * Metafile functions
 *
 * Copyright  David W. Metcalfe, 1994
5 6 7
 * Copyright  Niels de Carpentier, 1996
 * Copyright  Albrecht Kleine, 1996
 * Copyright  Huw Davies, 1996
Alexandre Julliard's avatar
Alexandre Julliard committed
8
 *
9 10 11 12 13 14 15 16 17 18 19 20
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
22 23 24
 *
 * NOTES
 *
25 26 27 28
 * These functions are primarily involved with metafile playback or anything
 * that touches a HMETAFILE.
 * For recording of metafiles look in graphics/metafiledrv/
 *
29
 * Note that (32 bit) HMETAFILEs are GDI objects, while HMETAFILE16s are
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 * global memory handles so these cannot be interchanged.
 *
 * Memory-based metafiles are just stored as a continuous block of memory with
 * a METAHEADER at the head with METARECORDs appended to it.  mtType is
 * METAFILE_MEMORY (1).  Note this is indentical to the disk image of a
 * disk-based metafile - even mtType is METAFILE_MEMORY.
 * 16bit HMETAFILE16s are global handles to this block
 * 32bit HMETAFILEs are GDI handles METAFILEOBJs, which contains a ptr to
 * the memory.
 * Disk-based metafiles are rather different. HMETAFILE16s point to a
 * METAHEADER which has mtType equal to METAFILE_DISK (2).  Following the 9
 * WORDs of the METAHEADER there are a further 3 WORDs of 0, 1 of 0x117, 1
 * more 0, then 2 which may be a time stamp of the file and then the path of
 * the file (METAHEADERDISK). I've copied this for 16bit compatibility.
 *
 * HDMD - 14/4/1999
46
 */
47

48
#include "config.h"
49

50
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
51
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
52
#include <fcntl.h>
53

54 55 56
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
57 58
#include "winreg.h"
#include "winternl.h"
59
#include "gdi_private.h"
60
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
61

62
WINE_DEFAULT_DEBUG_CHANNEL(metafile);
63

64 65 66 67 68 69 70 71 72
#include "pshpack1.h"
typedef struct
{
    DWORD dw1, dw2, dw3;
    WORD w4;
    CHAR filename[0x100];
} METAHEADERDISK;
#include "poppack.h"

73 74 75 76 77 78
typedef struct
{
    GDIOBJHDR   header;
    METAHEADER  *mh;
} METAFILEOBJ;

79

Alexandre Julliard's avatar
Alexandre Julliard committed
80 81 82 83 84
/******************************************************************
 *         MF_AddHandle
 *
 *    Add a handle to an external handle table and return the index
 */
85
static int MF_AddHandle(HANDLETABLE *ht, UINT htlen, HGDIOBJ hobj)
Alexandre Julliard's avatar
Alexandre Julliard committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
{
    int i;

    for (i = 0; i < htlen; i++)
    {
	if (*(ht->objectHandle + i) == 0)
	{
	    *(ht->objectHandle + i) = hobj;
	    return i;
	}
    }
    return -1;
}


/******************************************************************
102 103 104 105 106 107 108 109
 *         MF_Create_HMETATFILE
 *
 * Creates a (32 bit) HMETAFILE object from a METAHEADER
 *
 * HMETAFILEs are GDI objects.
 */
HMETAFILE MF_Create_HMETAFILE(METAHEADER *mh)
{
110
    HMETAFILE hmf = 0;
Michael Stefaniuc's avatar
Michael Stefaniuc committed
111 112
    METAFILEOBJ *metaObj = GDI_AllocObject( sizeof(METAFILEOBJ), METAFILE_MAGIC,
					    (HGDIOBJ *)&hmf, NULL );
113 114
    if (metaObj)
    {
115
        metaObj->mh = mh;
116 117
        GDI_ReleaseObj( hmf );
    }
118 119 120 121 122 123 124 125 126 127
    return hmf;
}

/******************************************************************
 *         MF_GetMetaHeader
 *
 * Returns ptr to METAHEADER associated with HMETAFILE
 */
static METAHEADER *MF_GetMetaHeader( HMETAFILE hmf )
{
128
    METAHEADER *ret = NULL;
129
    METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
130 131 132 133 134 135
    if (metaObj)
    {
        ret = metaObj->mh;
        GDI_ReleaseObj( hmf );
    }
    return ret;
136 137
}

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/******************************************************************
 *         convert_points
 *
 * Convert an array of POINT16 to an array of POINT.
 * Result must be freed by caller.
 */
static POINT *convert_points( UINT count, POINT16 *pt16 )
{
    UINT i;
    POINT *ret = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*ret) );
    if (ret)
    {
        for (i = 0; i < count; i++)
        {
            ret[i].x = pt16[i].x;
            ret[i].y = pt16[i].y;
        }
    }
    return ret;
}

159
/******************************************************************
160
 *          DeleteMetaFile  (GDI32.@)
161 162 163 164 165 166
 *
 *  Delete a memory-based metafile.
 */

BOOL WINAPI DeleteMetaFile( HMETAFILE hmf )
{
167 168 169 170
    METAFILEOBJ * metaObj = (METAFILEOBJ *)GDI_GetObjPtr( hmf, METAFILE_MAGIC );
    if (!metaObj) return FALSE;
    HeapFree( GetProcessHeap(), 0, metaObj->mh );
    GDI_FreeObject( hmf, metaObj );
171 172 173 174 175 176 177 178 179
    return TRUE;
}

/******************************************************************
 *         MF_ReadMetaFile
 *
 * Returns a pointer to a memory based METAHEADER read in from file HFILE
 *
 */
180
METAHEADER *MF_ReadMetaFile(HANDLE hfile)
181 182 183 184 185
{
    METAHEADER *mh;
    DWORD BytesRead, size;

    size = sizeof(METAHEADER);
186
    mh = HeapAlloc( GetProcessHeap(), 0, size );
187 188 189
    if(!mh) return NULL;
    if(ReadFile( hfile, mh, size, &BytesRead, NULL) == 0 ||
       BytesRead != size) {
190
        HeapFree( GetProcessHeap(), 0, mh );
191 192
	return NULL;
    }
193 194 195
    if (mh->mtType != METAFILE_MEMORY || mh->mtVersion != MFVERSION ||
        mh->mtHeaderSize != size / 2)
    {
196 197 198
        HeapFree( GetProcessHeap(), 0, mh );
        return NULL;
    }
199
    size = mh->mtSize * 2;
200
    mh = HeapReAlloc( GetProcessHeap(), 0, mh, size );
201 202 203 204 205
    if(!mh) return NULL;
    size -= sizeof(METAHEADER);
    if(ReadFile( hfile, (char *)mh + sizeof(METAHEADER), size, &BytesRead,
		 NULL) == 0 ||
       BytesRead != size) {
206
        HeapFree( GetProcessHeap(), 0, mh );
207 208 209 210
	return NULL;
    }

    if (mh->mtType != METAFILE_MEMORY) {
211
        WARN("Disk metafile had mtType = %04x\n", mh->mtType);
212 213 214 215 216
	mh->mtType = METAFILE_MEMORY;
    }
    return mh;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
217
/******************************************************************
218
 *         GetMetaFileA   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
219
 *
220
 *  Read a metafile from a file. Returns handle to a memory-based metafile.
Alexandre Julliard's avatar
Alexandre Julliard committed
221
 */
222
HMETAFILE WINAPI GetMetaFileA( LPCSTR lpFilename )
Alexandre Julliard's avatar
Alexandre Julliard committed
223
{
224
    METAHEADER *mh;
225
    HANDLE hFile;
226

227
    TRACE("%s\n", lpFilename);
228 229 230

    if(!lpFilename)
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
231

232
    if((hFile = CreateFileA(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
233
			    OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
234 235 236 237 238 239
        return 0;

    mh = MF_ReadMetaFile(hFile);
    CloseHandle(hFile);
    if(!mh) return 0;
    return MF_Create_HMETAFILE( mh );
Alexandre Julliard's avatar
Alexandre Julliard committed
240 241
}

Alexandre Julliard's avatar
Alexandre Julliard committed
242
/******************************************************************
243
 *         GetMetaFileW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
244
 */
245
HMETAFILE WINAPI GetMetaFileW( LPCWSTR lpFilename )
Alexandre Julliard's avatar
Alexandre Julliard committed
246
{
247
    METAHEADER *mh;
248
    HANDLE hFile;
249

250
    TRACE("%s\n", debugstr_w(lpFilename));
251 252 253 254

    if(!lpFilename)
        return 0;

255
    if((hFile = CreateFileW(lpFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
256
			    OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
257 258 259 260 261 262
        return 0;

    mh = MF_ReadMetaFile(hFile);
    CloseHandle(hFile);
    if(!mh) return 0;
    return MF_Create_HMETAFILE( mh );
Alexandre Julliard's avatar
Alexandre Julliard committed
263 264 265 266
}


/******************************************************************
267 268 269
 *         MF_LoadDiskBasedMetaFile
 *
 * Creates a new memory-based metafile from a disk-based one.
Alexandre Julliard's avatar
Alexandre Julliard committed
270
 */
271
METAHEADER *MF_LoadDiskBasedMetaFile(METAHEADER *mh)
272 273
{
    METAHEADERDISK *mhd;
274
    HANDLE hfile;
275
    METAHEADER *mh2;
Alexandre Julliard's avatar
Alexandre Julliard committed
276

277
    if(mh->mtType != METAFILE_DISK) {
278
        ERR("Not a disk based metafile\n");
279 280 281 282
	return NULL;
    }
    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 287 288 289 290 291 292 293 294 295 296
        return NULL;
    }
    mh2 = MF_ReadMetaFile(hfile);
    CloseHandle(hfile);
    return mh2;
}

/******************************************************************
 *         MF_CreateMetaHeaderDisk
 *
 * Take a memory based METAHEADER and change it to a disk based METAHEADER
297
 * assosiated with filename.  Note: Trashes contents of old one.
298
 */
299
METAHEADER *MF_CreateMetaHeaderDisk(METAHEADER *mh, LPCVOID filename, BOOL uni )
Alexandre Julliard's avatar
Alexandre Julliard committed
300
{
301 302
    METAHEADERDISK *mhd;

303
    mh = HeapReAlloc( GetProcessHeap(), 0, mh,
304 305 306
		      sizeof(METAHEADER) + sizeof(METAHEADERDISK));
    mh->mtType = METAFILE_DISK;
    mhd = (METAHEADERDISK *)((char *)mh + sizeof(METAHEADER));
307 308 309 310 311 312

    if( uni )
        WideCharToMultiByte(CP_ACP, 0, filename, -1, 
                   mhd->filename, sizeof mhd->filename, NULL, NULL);
    else
        lstrcpynA( mhd->filename, filename, sizeof mhd->filename );
313 314 315
    return mh;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
316
/******************************************************************
317
 *         CopyMetaFileW   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
318 319 320 321 322
 *
 *  Copies the metafile corresponding to hSrcMetaFile to either
 *  a disk file, if a filename is given, or to a new memory based
 *  metafile, if lpFileName is NULL.
 *
323 324 325
 * PARAMS
 *  hSrcMetaFile [I] handle of metafile to copy
 *  lpFilename   [I] filename if copying to a file
Alexandre Julliard's avatar
Alexandre Julliard committed
326
 *
327
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
328 329 330 331
 *  Handle to metafile copy on success, NULL on failure.
 *
 * BUGS
 *  Copying to disk returns NULL even if successful.
Alexandre Julliard's avatar
Alexandre Julliard committed
332
 */
333
HMETAFILE WINAPI CopyMetaFileW( HMETAFILE hSrcMetaFile, LPCWSTR lpFilename )
Jon Griffiths's avatar
Jon Griffiths committed
334
{
335 336
    METAHEADER *mh = MF_GetMetaHeader( hSrcMetaFile );
    METAHEADER *mh2 = NULL;
337
    HANDLE hFile;
338

339
    TRACE("(%p,%s)\n", hSrcMetaFile, debugstr_w(lpFilename));
340

341
    if(!mh) return 0;
342

343 344 345
    if(mh->mtType == METAFILE_DISK)
        mh2 = MF_LoadDiskBasedMetaFile(mh);
    else {
346
        mh2 = HeapAlloc( GetProcessHeap(), 0, mh->mtSize * 2 );
347 348 349 350
        memcpy( mh2, mh, mh->mtSize * 2 );
    }

    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 );
Alexandre Julliard's avatar
Alexandre Julliard committed
355
	    return 0;
356
	}
357
	WriteFile(hFile, mh2, mh2->mtSize * 2, &w, NULL);
358 359
	CloseHandle(hFile);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
360

361
    return MF_Create_HMETAFILE( mh2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
362 363
}

Alexandre Julliard's avatar
Alexandre Julliard committed
364 365

/******************************************************************
366
 *         CopyMetaFileA   (GDI32.@)
367 368
 *
 * See CopyMetaFileW.
Alexandre Julliard's avatar
Alexandre Julliard committed
369
 */
370
HMETAFILE WINAPI CopyMetaFileA( HMETAFILE hSrcMetaFile, LPCSTR lpFilename )
Alexandre Julliard's avatar
Alexandre Julliard committed
371
{
372
    UNICODE_STRING lpFilenameW;
373 374
    HMETAFILE ret = 0;

375 376 377
    if (lpFilename) RtlCreateUnicodeStringFromAsciiz(&lpFilenameW, lpFilename);
    else lpFilenameW.Buffer = NULL;

378 379 380
    ret = CopyMetaFileW( hSrcMetaFile, lpFilenameW.Buffer );
    if (lpFilenameW.Buffer)
        RtlFreeUnicodeString(&lpFilenameW);
Alexandre Julliard's avatar
Alexandre Julliard committed
381 382 383
    return ret;
}

384 385
/*******************************************************************
 *         MF_PlayMetaFile
Alexandre Julliard's avatar
Alexandre Julliard committed
386
 *
387
 * Helper for PlayMetaFile
Alexandre Julliard's avatar
Alexandre Julliard committed
388
 */
389
BOOL MF_PlayMetaFile( HDC hdc, METAHEADER *mh)
Alexandre Julliard's avatar
Alexandre Julliard committed
390 391
{

Alexandre Julliard's avatar
Alexandre Julliard committed
392
    METARECORD *mr;
393
    HANDLETABLE *ht;
394
    unsigned int offset = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
395
    WORD i;
396 397 398
    HPEN hPen;
    HBRUSH hBrush;
    HFONT hFont;
399 400
    BOOL loaded = FALSE;

Alexandre Julliard's avatar
Alexandre Julliard committed
401
    if (!mh) return FALSE;
402
    if(mh->mtType == METAFILE_DISK) { /* Create a memory-based copy */
403 404 405 406
        mh = MF_LoadDiskBasedMetaFile(mh);
	if(!mh) return FALSE;
	loaded = TRUE;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
407 408

    /* save the current pen, brush and font */
409 410 411 412
    hPen = GetCurrentObject(hdc, OBJ_PEN);
    hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
    hFont = GetCurrentObject(hdc, OBJ_FONT);

Alexandre Julliard's avatar
Alexandre Julliard committed
413
    /* create the handle table */
414
    ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
415
		    sizeof(HANDLETABLE) * mh->mtNoObjects);
416
    if(!ht) return FALSE;
417

Alexandre Julliard's avatar
Alexandre Julliard committed
418
    /* loop through metafile playing records */
Alexandre Julliard's avatar
Alexandre Julliard committed
419 420
    offset = mh->mtHeaderSize * 2;
    while (offset < mh->mtSize * 2)
Alexandre Julliard's avatar
Alexandre Julliard committed
421
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
422
        mr = (METARECORD *)((char *)mh + offset);
423
	TRACE("offset=%04x,size=%08x\n",
Alexandre Julliard's avatar
Alexandre Julliard committed
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 428
                  mr->rdSize,offset,mh->mtSize*2);
            break;
Alexandre Julliard's avatar
Alexandre Julliard committed
429
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
430
	offset += mr->rdSize * 2;
431
	PlayMetaFileRecord( hdc, ht, mr, mh->mtNoObjects );
Alexandre Julliard's avatar
Alexandre Julliard committed
432 433
    }

434 435 436
    SelectObject(hdc, hBrush);
    SelectObject(hdc, hPen);
    SelectObject(hdc, hFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
437

Alexandre Julliard's avatar
Alexandre Julliard committed
438 439 440
    /* free objects in handle table */
    for(i = 0; i < mh->mtNoObjects; i++)
      if(*(ht->objectHandle + i) != 0)
441
        DeleteObject(*(ht->objectHandle + i));
442

Alexandre Julliard's avatar
Alexandre Julliard committed
443
    /* free handle table */
444
    HeapFree( GetProcessHeap(), 0, ht );
445
    if(loaded)
446
        HeapFree( GetProcessHeap(), 0, mh );
Alexandre Julliard's avatar
Alexandre Julliard committed
447 448 449
    return TRUE;
}

450
/******************************************************************
451
 *         PlayMetaFile   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
452
 *
453 454
 *  Renders the metafile specified by hmf in the DC specified by
 *  hdc. Returns FALSE on failure, TRUE on success.
455 456 457 458
 *
 * PARAMS
 *  hdc [I] handle of DC to render in
 *  hmf [I] handle of metafile to render
459 460 461 462
 *
 * RETURNS
 *  Success: TRUE
 *  Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
463
 */
464
BOOL WINAPI PlayMetaFile( HDC hdc, HMETAFILE hmf )
Alexandre Julliard's avatar
Alexandre Julliard committed
465
{
466
    METAHEADER *mh = MF_GetMetaHeader( hmf );
467
    return MF_PlayMetaFile( hdc, mh );
468 469 470
}

/******************************************************************
471
 *            EnumMetaFile   (GDI32.@)
472 473 474 475
 *
 *  Loop through the metafile records in hmf, calling the user-specified
 *  function for each one, stopping when the user's function returns FALSE
 *  (which is considered to be failure)
476
 *  or when no records are left (which is considered to be success).
477 478 479 480
 *
 * RETURNS
 *  TRUE on success, FALSE on failure.
 */
481
BOOL WINAPI EnumMetaFile(HDC hdc, HMETAFILE hmf, MFENUMPROC lpEnumFunc, LPARAM lpData)
Jon Griffiths's avatar
Jon Griffiths committed
482
{
Alexandre Julliard's avatar
Alexandre Julliard committed
483
    METAHEADER *mhTemp = NULL, *mh = MF_GetMetaHeader(hmf);
Alexandre Julliard's avatar
Alexandre Julliard committed
484
    METARECORD *mr;
485
    HANDLETABLE *ht;
Alexandre Julliard's avatar
Alexandre Julliard committed
486
    BOOL result = TRUE;
487 488
    int i;
    unsigned int offset = 0;
489 490 491
    HPEN hPen;
    HBRUSH hBrush;
    HFONT hFont;
Alexandre Julliard's avatar
Alexandre Julliard committed
492

493
    TRACE("(%p,%p,%p,%p)\n", hdc, hmf, lpEnumFunc, (void*)lpData);
Alexandre Julliard's avatar
Alexandre Julliard committed
494
    if (!mh) return 0;
495
    if(mh->mtType == METAFILE_DISK)
Alexandre Julliard's avatar
Alexandre Julliard committed
496
    {
497 498
        /* Create a memory-based copy */
        if (!(mhTemp = MF_LoadDiskBasedMetaFile(mh))) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
499 500
	mh = mhTemp;
    }
501

Alexandre Julliard's avatar
Alexandre Julliard committed
502
    /* save the current pen, brush and font */
503 504 505
    hPen = GetCurrentObject(hdc, OBJ_PEN);
    hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
    hFont = GetCurrentObject(hdc, OBJ_FONT);
Alexandre Julliard's avatar
Alexandre Julliard committed
506

507
    ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
508
			    sizeof(HANDLETABLE) * mh->mtNoObjects);
509

Alexandre Julliard's avatar
Alexandre Julliard committed
510 511
    /* loop through metafile records */
    offset = mh->mtHeaderSize * 2;
512

Alexandre Julliard's avatar
Alexandre Julliard committed
513 514 515
    while (offset < (mh->mtSize * 2))
    {
	mr = (METARECORD *)((char *)mh + offset);
516 517 518 519
	if(mr->rdFunction == META_EOF) {
	    TRACE("Got META_EOF so stopping\n");
	    break;
	}
520
	TRACE("Calling EnumFunc with record type %x\n",
521
	      mr->rdFunction);
Alexandre Julliard's avatar
Alexandre Julliard committed
522 523 524 525 526
        if (!lpEnumFunc( hdc, ht, mr, mh->mtNoObjects, (LONG)lpData ))
	{
	    result = FALSE;
	    break;
	}
527

Alexandre Julliard's avatar
Alexandre Julliard committed
528 529 530 531
	offset += (mr->rdSize * 2);
    }

    /* restore pen, brush and font */
532 533 534
    SelectObject(hdc, hBrush);
    SelectObject(hdc, hPen);
    SelectObject(hdc, hFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
535 536 537 538

    /* free objects in handle table */
    for(i = 0; i < mh->mtNoObjects; i++)
      if(*(ht->objectHandle + i) != 0)
539
        DeleteObject(*(ht->objectHandle + i));
Alexandre Julliard's avatar
Alexandre Julliard committed
540 541

    /* free handle table */
542
    HeapFree( GetProcessHeap(), 0, ht);
Alexandre Julliard's avatar
Alexandre Julliard committed
543
    /* free a copy of metafile */
544
    HeapFree( GetProcessHeap(), 0, mhTemp );
Alexandre Julliard's avatar
Alexandre Julliard committed
545 546 547
    return result;
}

548
static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn );
549
static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr);
Alexandre Julliard's avatar
Alexandre Julliard committed
550
/******************************************************************
551
 *         PlayMetaFileRecord   (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
552 553
 *
 *   Render a single metafile record specified by *mr in the DC hdc, while
554
 *   using the handle table *ht, of length handles,
Alexandre Julliard's avatar
Alexandre Julliard committed
555 556 557 558 559
 *   to store metafile objects.
 *
 * BUGS
 *  The following metafile records are unimplemented:
 *
560
 *  DRAWTEXT, ANIMATEPALETTE, SETPALENTRIES,
Alexandre Julliard's avatar
Alexandre Julliard committed
561 562
 *  RESIZEPALETTE, EXTFLOODFILL, RESETDC, STARTDOC, STARTPAGE, ENDPAGE,
 *  ABORTDOC, ENDDOC, CREATEBRUSH, CREATEBITMAPINDIRECT, and CREATEBITMAP.
Alexandre Julliard's avatar
Alexandre Julliard committed
563
 */
564 565
BOOL WINAPI PlayMetaFileRecord( HDC hdc,  HANDLETABLE *ht, METARECORD *mr, UINT handles )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
566
    short s1;
567
    POINT *pt;
Alexandre Julliard's avatar
Alexandre Julliard committed
568 569
    BITMAPINFOHEADER *infohdr;

570
    TRACE("(%p %p %p %u) function %04x\n", hdc, ht, mr, handles, mr->rdFunction);
571

Alexandre Julliard's avatar
Alexandre Julliard committed
572 573
    switch (mr->rdFunction)
    {
Alexandre Julliard's avatar
Alexandre Julliard committed
574
    case META_EOF:
575
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
576 577

    case META_DELETEOBJECT:
578 579 580
        DeleteObject(*(ht->objectHandle + mr->rdParm[0]));
        *(ht->objectHandle + mr->rdParm[0]) = 0;
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
581

Alexandre Julliard's avatar
Alexandre Julliard committed
582
    case META_SETBKCOLOR:
583 584
        SetBkColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
585 586

    case META_SETBKMODE:
587 588
        SetBkMode(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
589 590

    case META_SETMAPMODE:
591 592
        SetMapMode(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
593 594

    case META_SETROP2:
595 596
        SetROP2(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
597 598

    case META_SETRELABS:
599 600
        SetRelAbs(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
601 602

    case META_SETPOLYFILLMODE:
603 604
        SetPolyFillMode(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
605 606

    case META_SETSTRETCHBLTMODE:
607 608
        SetStretchBltMode(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
609

Alexandre Julliard's avatar
Alexandre Julliard committed
610
    case META_SETTEXTCOLOR:
611 612
        SetTextColor(hdc, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
613 614

    case META_SETWINDOWORG:
615 616
        SetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
617 618

    case META_SETWINDOWEXT:
619 620
        SetWindowExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
621 622

    case META_SETVIEWPORTORG:
623 624
        SetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
625 626

    case META_SETVIEWPORTEXT:
627 628
        SetViewportExtEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
629 630

    case META_OFFSETWINDOWORG:
631 632
        OffsetWindowOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
633 634

    case META_SCALEWINDOWEXT:
635 636 637
        ScaleWindowExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                              (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
638 639

    case META_OFFSETVIEWPORTORG:
640 641
        OffsetViewportOrgEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
642 643

    case META_SCALEVIEWPORTEXT:
644 645 646
        ScaleViewportExtEx(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                                (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
647 648

    case META_LINETO:
649 650
        LineTo(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
651 652

    case META_MOVETO:
653 654
        MoveToEx(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0], NULL);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
655 656

    case META_EXCLUDECLIPRECT:
657 658 659
        ExcludeClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                              (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
660 661

    case META_INTERSECTCLIPRECT:
662 663 664
        IntersectClipRect( hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                                (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
665 666

    case META_ARC:
667 668 669 670 671
        Arc(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
                 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
672 673

    case META_ELLIPSE:
674 675 676
        Ellipse(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                     (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
677 678

    case META_FLOODFILL:
679 680 681
        FloodFill(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                    MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
682 683

    case META_PIE:
684 685 686 687 688
        Pie(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
                 (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                 (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
689 690

    case META_RECTANGLE:
691 692 693
        Rectangle(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                       (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
694 695

    case META_ROUNDRECT:
696 697 698 699
        RoundRect(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                       (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                       (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
700 701

    case META_PATBLT:
702 703 704 705
        PatBlt(hdc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                    (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                    MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
706 707

    case META_SAVEDC:
708 709
        SaveDC(hdc);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
710 711

    case META_SETPIXEL:
712 713 714
        SetPixel(hdc, (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                 MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
715 716

    case META_OFFSETCLIPRGN:
717 718
        OffsetClipRgn( hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0] );
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
719 720

    case META_TEXTOUT:
721 722 723 724 725
        s1 = mr->rdParm[0];
        TextOutA(hdc, (SHORT)mr->rdParm[((s1 + 1) >> 1) + 2],
                 (SHORT)mr->rdParm[((s1 + 1) >> 1) + 1],
                 (char *)(mr->rdParm + 1), s1);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
726 727

    case META_POLYGON:
728 729 730 731 732 733
        if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
        {
            Polygon(hdc, pt, mr->rdParm[0]);
            HeapFree( GetProcessHeap(), 0, pt );
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
734

Alexandre Julliard's avatar
Alexandre Julliard committed
735
    case META_POLYPOLYGON:
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754
        {
            UINT i, total;
            SHORT *counts = (SHORT *)(mr->rdParm + 1);

            for (i = total = 0; i < mr->rdParm[0]; i++) total += counts[i];
            pt = convert_points( total, (LPPOINT16)(counts + mr->rdParm[0]) );
            if (pt)
            {
                INT *cnt32 = HeapAlloc( GetProcessHeap(), 0, mr->rdParm[0] * sizeof(*cnt32) );
                if (cnt32)
                {
                    for (i = 0; i < mr->rdParm[0]; i++) cnt32[i] = counts[i];
                    PolyPolygon( hdc, pt, cnt32, mr->rdParm[0]);
                    HeapFree( GetProcessHeap(), 0, cnt32 );
                }
            }
            HeapFree( GetProcessHeap(), 0, pt );
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
755

Alexandre Julliard's avatar
Alexandre Julliard committed
756
    case META_POLYLINE:
757 758 759 760 761 762
        if ((pt = convert_points( mr->rdParm[0], (LPPOINT16)(mr->rdParm + 1))))
        {
            Polyline( hdc, pt, mr->rdParm[0] );
            HeapFree( GetProcessHeap(), 0, pt );
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
763 764

    case META_RESTOREDC:
765 766
        RestoreDC(hdc, (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
767 768

    case META_SELECTOBJECT:
769 770
        SelectObject(hdc, *(ht->objectHandle + mr->rdParm[0]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
771 772

    case META_CHORD:
773 774 775 776 777
        Chord(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
                   (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                   (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                   (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
778 779

    case META_CREATEPATTERNBRUSH:
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803
        switch (mr->rdParm[0])
        {
        case BS_PATTERN:
            infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
            MF_AddHandle(ht, handles,
                         CreatePatternBrush(CreateBitmap(infohdr->biWidth,
                                      infohdr->biHeight,
                                      infohdr->biPlanes,
                                      infohdr->biBitCount,
                                      (LPSTR)(mr->rdParm +
                                      (sizeof(BITMAPINFOHEADER) / 2) + 4))));
            break;

        case BS_DIBPATTERN:
            infohdr = (BITMAPINFOHEADER *)(mr->rdParm + 2);
            MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( infohdr, mr->rdParm[1] ));
            break;

        default:
            ERR("META_CREATEPATTERNBRUSH: Unknown pattern type %d\n",
                mr->rdParm[0]);
            break;
        }
        break;
804

Alexandre Julliard's avatar
Alexandre Julliard committed
805
    case META_CREATEPENINDIRECT:
806 807 808 809 810 811 812 813 814
        {
            LOGPEN pen;
            pen.lopnStyle = mr->rdParm[0];
            pen.lopnWidth.x = (SHORT)mr->rdParm[1];
            pen.lopnWidth.y = (SHORT)mr->rdParm[2];
            pen.lopnColor = MAKELONG( mr->rdParm[3], mr->rdParm[4] );
            MF_AddHandle(ht, handles, CreatePenIndirect( &pen ));
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
815

Alexandre Julliard's avatar
Alexandre Julliard committed
816
    case META_CREATEFONTINDIRECT:
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835
        {
            LOGFONTA font;
            font.lfHeight         = (SHORT)mr->rdParm[0];
            font.lfWidth          = (SHORT)mr->rdParm[1];
            font.lfEscapement     = (SHORT)mr->rdParm[2];
            font.lfOrientation    = (SHORT)mr->rdParm[3];
            font.lfWeight         = (SHORT)mr->rdParm[4];
            font.lfItalic         = LOBYTE(mr->rdParm[5]);
            font.lfUnderline      = HIBYTE(mr->rdParm[5]);
            font.lfStrikeOut      = LOBYTE(mr->rdParm[6]);
            font.lfCharSet        = HIBYTE(mr->rdParm[6]);
            font.lfOutPrecision   = LOBYTE(mr->rdParm[7]);
            font.lfClipPrecision  = HIBYTE(mr->rdParm[7]);
            font.lfQuality        = LOBYTE(mr->rdParm[8]);
            font.lfPitchAndFamily = HIBYTE(mr->rdParm[8]);
            memcpy( font.lfFaceName, mr->rdParm + 9, LF_FACESIZE );
            MF_AddHandle(ht, handles, CreateFontIndirectA( &font ));
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
836

Alexandre Julliard's avatar
Alexandre Julliard committed
837
    case META_CREATEBRUSHINDIRECT:
838 839 840 841 842 843 844 845
        {
            LOGBRUSH brush;
            brush.lbStyle = mr->rdParm[0];
            brush.lbColor = MAKELONG( mr->rdParm[1], mr->rdParm[2] );
            brush.lbHatch = mr->rdParm[3];
            MF_AddHandle(ht, handles, CreateBrushIndirect( &brush ));
        }
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
846

Alexandre Julliard's avatar
Alexandre Julliard committed
847
    case META_CREATEPALETTE:
848 849
        MF_AddHandle(ht, handles, CreatePalette((LPLOGPALETTE)mr->rdParm));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
850 851

    case META_SETTEXTALIGN:
852 853
        SetTextAlign(hdc, mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
854 855

    case META_SELECTPALETTE:
856 857
        GDISelectPalette(hdc, *(ht->objectHandle + mr->rdParm[1]), mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
858 859

    case META_SETMAPPERFLAGS:
860 861
        SetMapperFlags(hdc, MAKELONG(mr->rdParm[0],mr->rdParm[1]));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
862 863

    case META_REALIZEPALETTE:
864 865
        GDIRealizePalette(hdc);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
866 867

    case META_ESCAPE:
868 869
        switch (mr->rdParm[0]) {
        case GETSCALINGFACTOR: /* get function ... would just NULL dereference */
870 871
        case GETPHYSPAGESIZE:
        case GETPRINTINGOFFSET:
872 873 874 875 876
             return FALSE;
        case SETABORTPROC:
             FIXME("Filtering Escape(SETABORTPROC), possible virus?\n");
             return FALSE;
        }
877
        Escape(hdc, mr->rdParm[0], mr->rdParm[1], (LPCSTR)&mr->rdParm[2], NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
878 879
        break;

Alexandre Julliard's avatar
Alexandre Julliard committed
880
    case META_EXTTEXTOUT:
881
        MF_Play_MetaExtTextOut( hdc, mr );
882
        break;
883

Alexandre Julliard's avatar
Alexandre Julliard committed
884 885
    case META_STRETCHDIB:
      {
886 887 888 889 890
        LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[11]);
        LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
        StretchDIBits( hdc, (SHORT)mr->rdParm[10], (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
                       (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
                       (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], bits, info,
891
                       mr->rdParm[2],MAKELONG(mr->rdParm[0],mr->rdParm[1]));
Alexandre Julliard's avatar
Alexandre Julliard committed
892 893
      }
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
894 895 896

    case META_DIBSTRETCHBLT:
      {
897 898 899 900 901
        LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[10]);
        LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize( info, mr->rdParm[2] );
        StretchDIBits( hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
                       (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                       (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2], bits, info,
902
                       DIB_RGB_COLORS,MAKELONG(mr->rdParm[0],mr->rdParm[1]));
Alexandre Julliard's avatar
Alexandre Julliard committed
903
      }
904
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
905 906 907

    case META_STRETCHBLT:
      {
908 909 910 911 912 913 914 915 916 917 918 919 920
        HDC hdcSrc = CreateCompatibleDC(hdc);
        HBITMAP hbitmap = CreateBitmap(mr->rdParm[10], /*Width */
                                       mr->rdParm[11], /*Height*/
                                       mr->rdParm[13], /*Planes*/
                                       mr->rdParm[14], /*BitsPixel*/
                                       (LPSTR)&mr->rdParm[15]);  /*bits*/
        SelectObject(hdcSrc,hbitmap);
        StretchBlt(hdc, (SHORT)mr->rdParm[9], (SHORT)mr->rdParm[8],
                   (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6],
                   hdcSrc, (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4],
                   (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                   MAKELONG(mr->rdParm[0],mr->rdParm[1]));
        DeleteDC(hdcSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
921 922 923
      }
      break;

924
    case META_BITBLT:
Alexandre Julliard's avatar
Alexandre Julliard committed
925
      {
926 927
        HDC hdcSrc = CreateCompatibleDC(hdc);
        HBITMAP hbitmap = CreateBitmap(mr->rdParm[7]/*Width */,
928 929 930 931
                                        mr->rdParm[8]/*Height*/,
                                        mr->rdParm[10]/*Planes*/,
                                        mr->rdParm[11]/*BitsPixel*/,
                                        (LPSTR)&mr->rdParm[12]/*bits*/);
932 933 934 935
        SelectObject(hdcSrc,hbitmap);
        BitBlt(hdc,(SHORT)mr->rdParm[6],(SHORT)mr->rdParm[5],
                (SHORT)mr->rdParm[4],(SHORT)mr->rdParm[3],
                hdcSrc, (SHORT)mr->rdParm[2],(SHORT)mr->rdParm[1],
936
                MAKELONG(0,mr->rdParm[0]));
937
        DeleteDC(hdcSrc);
Alexandre Julliard's avatar
Alexandre Julliard committed
938 939
      }
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
940 941

    case META_CREATEREGION:
Alexandre Julliard's avatar
Alexandre Julliard committed
942
      {
943
        HRGN hrgn = CreateRectRgn(0,0,0,0);
944

945 946
        MF_Play_MetaCreateRegion(mr, hrgn);
        MF_AddHandle(ht, handles, hrgn);
Alexandre Julliard's avatar
Alexandre Julliard committed
947 948
      }
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
949

950
    case META_FILLREGION:
951 952
        FillRgn(hdc, *(ht->objectHandle + mr->rdParm[1]),
                *(ht->objectHandle + mr->rdParm[0]));
953 954 955
        break;

    case META_FRAMEREGION:
956 957 958
        FrameRgn(hdc, *(ht->objectHandle + mr->rdParm[3]),
                 *(ht->objectHandle + mr->rdParm[2]),
                 (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
Alexandre Julliard's avatar
Alexandre Julliard committed
959 960
        break;

961
    case META_INVERTREGION:
962
        InvertRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
963
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
964

965
    case META_PAINTREGION:
966
        PaintRgn(hdc, *(ht->objectHandle + mr->rdParm[0]));
Alexandre Julliard's avatar
Alexandre Julliard committed
967 968
        break;

969
    case META_SELECTCLIPREGION:
970 971 972 973 974 975
        {
            HRGN hrgn = 0;

            if (mr->rdParm[0]) hrgn = *(ht->objectHandle + mr->rdParm[0]);
            SelectClipRgn(hdc, hrgn);
        }
976
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
977

978
    case META_DIBCREATEPATTERNBRUSH:
979 980 981 982
        /*  mr->rdParm[0] may be BS_PATTERN or BS_DIBPATTERN:
            but there's no difference */
        MF_AddHandle(ht, handles, CreateDIBPatternBrushPt( mr->rdParm + 2, mr->rdParm[1] ));
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
983

984 985
    case META_DIBBITBLT:
      /* In practice I've found that there are two layouts for
986 987 988 989
         META_DIBBITBLT, one (the first here) is the usual one when a src
         dc is actually passed to it, the second occurs when the src dc is
         passed in as NULL to the creating BitBlt. As the second case has
         no dib, a size check will suffice to distinguish.
990

991
         Caolan.McNamara@ul.ie */
992 993

        if (mr->rdSize > 12) {
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
            LPBITMAPINFO info = (LPBITMAPINFO) &(mr->rdParm[8]);
            LPSTR bits = (LPSTR)info + DIB_BitmapInfoSize(info, mr->rdParm[0]);

            StretchDIBits(hdc, (SHORT)mr->rdParm[7], (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
                          (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3], (SHORT)mr->rdParm[2],
                          (SHORT)mr->rdParm[5], (SHORT)mr->rdParm[4], bits, info,
                          DIB_RGB_COLORS, MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        }
        else /* equivalent to a PatBlt */
            PatBlt(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
                   (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
                   MAKELONG(mr->rdParm[0], mr->rdParm[1]));
        break;
1007

1008
    case META_SETTEXTCHAREXTRA:
1009 1010
        SetTextCharacterExtra(hdc, (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1011

1012
    case META_SETTEXTJUSTIFICATION:
1013 1014
        SetTextJustification(hdc, (SHORT)mr->rdParm[1], (SHORT)mr->rdParm[0]);
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1015

1016
    case META_EXTFLOODFILL:
1017 1018 1019
        ExtFloodFill(hdc, (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
                     MAKELONG(mr->rdParm[1], mr->rdParm[2]),
                     mr->rdParm[0]);
1020 1021
        break;

1022
    case META_SETDIBTODEV:
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
        {
            BITMAPINFO *info = (BITMAPINFO *) &(mr->rdParm[9]);
            char *bits = (char *)info + DIB_BitmapInfoSize( info, mr->rdParm[0] );
            SetDIBitsToDevice(hdc, (SHORT)mr->rdParm[8], (SHORT)mr->rdParm[7],
                              (SHORT)mr->rdParm[6], (SHORT)mr->rdParm[5],
                              (SHORT)mr->rdParm[4], (SHORT)mr->rdParm[3],
                              mr->rdParm[2], mr->rdParm[1], bits, info,
                              mr->rdParm[0]);
            break;
        }
1033 1034

#define META_UNIMP(x) case x: \
1035
FIXME("PlayMetaFileRecord:record type "#x" not implemented.\n"); \
1036
break;
Alexandre Julliard's avatar
Alexandre Julliard committed
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050
    META_UNIMP(META_DRAWTEXT)
    META_UNIMP(META_ANIMATEPALETTE)
    META_UNIMP(META_SETPALENTRIES)
    META_UNIMP(META_RESIZEPALETTE)
    META_UNIMP(META_RESETDC)
    META_UNIMP(META_STARTDOC)
    META_UNIMP(META_STARTPAGE)
    META_UNIMP(META_ENDPAGE)
    META_UNIMP(META_ABORTDOC)
    META_UNIMP(META_ENDDOC)
    META_UNIMP(META_CREATEBRUSH)
    META_UNIMP(META_CREATEBITMAPINDIRECT)
    META_UNIMP(META_CREATEBITMAP)
#undef META_UNIMP
Alexandre Julliard's avatar
Alexandre Julliard committed
1051

Alexandre Julliard's avatar
Alexandre Julliard committed
1052
    default:
1053 1054
        WARN("PlayMetaFileRecord: Unknown record type %x\n", mr->rdFunction);
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1055
    }
1056
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1057 1058 1059
}

/******************************************************************
1060
 *         SetMetaFileBitsEx    (GDI32.@)
1061
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1062
 *  Create a metafile from raw data. No checking of the data is performed.
1063 1064 1065 1066 1067
 *  Use GetMetaFileBitsEx() to get raw data from a metafile.
 *
 * PARAMS
 *  size   [I] size of metafile, in bytes
 *  lpData [I] pointer to metafile data
1068 1069 1070 1071
 *
 * RETURNS
 *  Success: Handle to metafile.
 *  Failure: NULL.
Alexandre Julliard's avatar
Alexandre Julliard committed
1072
 */
1073
HMETAFILE WINAPI SetMetaFileBitsEx( UINT size, const BYTE *lpData )
Alexandre Julliard's avatar
Alexandre Julliard committed
1074
{
1075 1076
    const METAHEADER *mh_in = (const METAHEADER *)lpData;
    METAHEADER *mh_out;
1077 1078 1079

    if (size & 1) return 0;

1080 1081
    if (!size || mh_in->mtType != METAFILE_MEMORY || mh_in->mtVersion != MFVERSION ||
        mh_in->mtHeaderSize != sizeof(METAHEADER) / 2)
1082 1083 1084 1085 1086
    {
        SetLastError(ERROR_INVALID_DATA);
        return 0;
    }

1087 1088
    mh_out = HeapAlloc( GetProcessHeap(), 0, size );
    if (!mh_out)
1089 1090 1091 1092 1093
    {
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return 0;
    }

1094 1095 1096
    memcpy(mh_out, mh_in, size);
    mh_out->mtSize = size / 2;
    return MF_Create_HMETAFILE(mh_out);
Alexandre Julliard's avatar
Alexandre Julliard committed
1097 1098
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1099
/*****************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
1100 1101 1102
 *  GetMetaFileBitsEx     (GDI32.@)
 *
 * Get raw metafile data.
1103
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
 *  Copies the data from metafile _hmf_ into the buffer _buf_.
1105 1106 1107 1108 1109
 *
 * PARAMS
 *  hmf   [I] metafile
 *  nSize [I] size of buf
 *  buf   [O] buffer to receive raw metafile data
1110 1111 1112 1113
 *
 * RETURNS
 *  If _buf_ is zero, returns size of buffer required. Otherwise,
 *  returns number of bytes copied.
Alexandre Julliard's avatar
Alexandre Julliard committed
1114
 */
1115
UINT WINAPI GetMetaFileBitsEx( HMETAFILE hmf, UINT nSize, LPVOID buf )
Jon Griffiths's avatar
Jon Griffiths committed
1116
{
1117 1118 1119
    METAHEADER *mh = MF_GetMetaHeader(hmf);
    UINT mfSize;

1120
    TRACE("(%p,%d,%p)\n", hmf, nSize, buf);
1121 1122
    if (!mh) return 0;  /* FIXME: error code */
    if(mh->mtType == METAFILE_DISK)
1123
        FIXME("Disk-based metafile?\n");
1124 1125
    mfSize = mh->mtSize * 2;
    if (!buf) {
1126
	TRACE("returning size %d\n", mfSize);
1127 1128 1129 1130
	return mfSize;
    }
    if(mfSize > nSize) mfSize = nSize;
    memmove(buf, mh, mfSize);
1131
    return mfSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1132 1133
}

1134
/******************************************************************
1135
 *         GetWinMetaFileBits [GDI32.@]
1136
 */
1137 1138 1139
UINT WINAPI GetWinMetaFileBits(HENHMETAFILE hemf,
                                UINT cbBuffer, LPBYTE lpbBuffer,
                                INT fnMapMode, HDC hdcRef)
1140
{
1141 1142 1143
    HDC hdcmf;
    HMETAFILE hmf;
    UINT ret;
1144 1145 1146 1147 1148 1149 1150 1151
    RECT rc;
    INT oldMapMode;

    GetClipBox(hdcRef, &rc);
    oldMapMode = SetMapMode(hdcRef, fnMapMode);

    TRACE("(%p,%d,%p,%d,%p) rc=%s\n", hemf, cbBuffer, lpbBuffer,
        fnMapMode, hdcRef, wine_dbgstr_rect(&rc));
1152 1153

    hdcmf = CreateMetaFileA(NULL);
1154
    PlayEnhMetaFile(hdcmf, hemf, &rc);
1155 1156 1157
    hmf = CloseMetaFile(hdcmf);
    ret = GetMetaFileBitsEx(hmf, cbBuffer, lpbBuffer);
    DeleteMetaFile(hmf);
1158 1159 1160

    SetMapMode(hdcRef, oldMapMode);

1161
    return ret;
1162
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1163

Alexandre Julliard's avatar
Alexandre Julliard committed
1164
/******************************************************************
1165
 *         MF_Play_MetaCreateRegion
Alexandre Julliard's avatar
Alexandre Julliard committed
1166 1167
 *
 *  Handles META_CREATEREGION for PlayMetaFileRecord().
1168
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
1169
 *	The layout of the record looks something like this:
1170
 *
1171
 *	 rdParm	meaning
Alexandre Julliard's avatar
Alexandre Julliard committed
1172 1173 1174 1175 1176
 *	 0		Always 0?
 *	 1		Always 6?
 *	 2		Looks like a handle? - not constant
 *	 3		0 or 1 ??
 *	 4		Total number of bytes
1177
 *	 5		No. of separate bands = n [see below]
Alexandre Julliard's avatar
Alexandre Julliard committed
1178 1179 1180 1181 1182 1183 1184 1185
 *	 6		Largest number of x co-ords in a band
 *	 7-10		Bounding box x1 y1 x2 y2
 *	 11-...		n bands
 *
 *	 Regions are divided into bands that are uniform in the
 *	 y-direction. Each band consists of pairs of on/off x-coords and is
 *	 written as
 *		m y0 y1 x1 x2 x3 ... xm m
1186
 *	 into successive rdParm[]s.
Alexandre Julliard's avatar
Alexandre Julliard committed
1187 1188 1189 1190 1191 1192 1193
 *
 *	 This is probably just a dump of the internal RGNOBJ?
 *
 *	 HDMD - 18/12/97
 *
 */

1194
static BOOL MF_Play_MetaCreateRegion( METARECORD *mr, HRGN hrgn )
Alexandre Julliard's avatar
Alexandre Julliard committed
1195 1196 1197 1198
{
    WORD band, pair;
    WORD *start, *end;
    INT16 y0, y1;
1199
    HRGN hrgn2 = CreateRectRgn( 0, 0, 0, 0 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1200

1201
    for(band  = 0, start = &(mr->rdParm[11]); band < mr->rdParm[5];
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203
 					        band++, start = end + 1) {
        if(*start / 2 != (*start + 1) / 2) {
1204
 	    WARN("Delimiter not even.\n");
1205
	    DeleteObject( hrgn2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1206 1207 1208 1209 1210
 	    return FALSE;
        }

	end = start + *start + 3;
	if(end > (WORD *)mr + mr->rdSize) {
1211
	    WARN("End points outside record.\n");
1212
	    DeleteObject( hrgn2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1213 1214 1215 1216
	    return FALSE;
        }

	if(*start != *end) {
1217
	    WARN("Mismatched delimiters.\n");
1218
	    DeleteObject( hrgn2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1219 1220 1221 1222 1223 1224
	    return FALSE;
	}

	y0 = *(INT16 *)(start + 1);
	y1 = *(INT16 *)(start + 2);
	for(pair = 0; pair < *start / 2; pair++) {
1225
	    SetRectRgn( hrgn2, *(INT16 *)(start + 3 + 2*pair), y0,
Alexandre Julliard's avatar
Alexandre Julliard committed
1226
				 *(INT16 *)(start + 4 + 2*pair), y1 );
1227
	    CombineRgn(hrgn, hrgn, hrgn2, RGN_OR);
Alexandre Julliard's avatar
Alexandre Julliard committed
1228 1229
        }
    }
1230
    DeleteObject( hrgn2 );
Alexandre Julliard's avatar
Alexandre Julliard committed
1231 1232
    return TRUE;
 }
1233

Alexandre Julliard's avatar
Alexandre Julliard committed
1234

1235 1236 1237 1238
/******************************************************************
 *         MF_Play_MetaExtTextOut
 *
 *  Handles META_EXTTEXTOUT for PlayMetaFileRecord().
Alexandre Julliard's avatar
Alexandre Julliard committed
1239
 */
1240

1241
static BOOL MF_Play_MetaExtTextOut(HDC hdc, METARECORD *mr)
1242
{
1243 1244
    INT *dx = NULL;
    int i;
1245
    LPINT16 dxx;
1246
    LPSTR sot;
1247 1248
    DWORD len;
    WORD s1;
1249
    RECT rect;
1250
    BOOL isrect = mr->rdParm[3] & (ETO_OPAQUE | ETO_CLIPPED);
1251 1252 1253

    s1 = mr->rdParm[2];                              /* String length */
    len = sizeof(METARECORD) + (((s1 + 1) >> 1) * 2) + 2 * sizeof(short)
1254
      + sizeof(UINT16) + (isrect ? sizeof(RECT16) : 0);
1255 1256 1257
                                           /* rec len without dx array */

    sot = (LPSTR)&mr->rdParm[4];		      /* start_of_text */
1258
    if (isrect)
1259 1260 1261 1262 1263
    {
        rect.left   = (SHORT)mr->rdParm[4];
        rect.top    = (SHORT)mr->rdParm[5];
        rect.right  = (SHORT)mr->rdParm[6];
        rect.bottom = (SHORT)mr->rdParm[7];
1264
        sot += sizeof(RECT16);  /* there is a rectangle, so add offset */
1265
    }
1266

1267 1268
    if (mr->rdSize == len / 2)
        dxx = NULL;                      /* determine if array present */
1269
    else
1270
        if (mr->rdSize == (len + s1 * sizeof(INT16)) / 2)
1271 1272 1273 1274 1275
        {
            dxx = (LPINT16)(sot+(((s1+1)>>1)*2));
            dx = HeapAlloc( GetProcessHeap(), 0, s1*sizeof(INT));
            if (dx) for (i = 0; i < s1; i++) dx[i] = (SHORT)dxx[i];
        }
1276
	else {
1277 1278
            TRACE("%s  len: %d\n",  sot, mr->rdSize);
            WARN("Please report: ExtTextOut len=%d slen=%d rdSize=%d opt=%04x\n",
1279 1280 1281
		 len, s1, mr->rdSize, mr->rdParm[3]);
	    dxx = NULL; /* should't happen -- but if, we continue with NULL */
	}
1282 1283 1284 1285 1286 1287
    ExtTextOutA( hdc,
                 (SHORT)mr->rdParm[1],       /* X position */
                 (SHORT)mr->rdParm[0],       /* Y position */
                 mr->rdParm[3],              /* options */
                 &rect,                      /* rectangle */
                 sot,                        /* string */
1288
                 s1, dx);                    /* length, dx array */
1289 1290
    if (dx)
    {
1291
        TRACE("%s  len: %d  dx0: %d\n", sot, mr->rdSize, dx[0]);
1292 1293
        HeapFree( GetProcessHeap(), 0, dx );
    }
1294 1295
    return TRUE;
}