enhmetafile.c 84.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
2 3
 * Enhanced metafile functions
 * Copyright 1998 Douglas Ridgway
4
 *           1999 Huw D M Davies
5
 *
6 7 8 9 10 11 12 13 14 15 16 17
 * 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
18
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 20 21
 *
 * NOTES:
 *
22
 * The enhanced format consists of the following elements:
23
 *
24 25 26 27
 *    A header
 *    A table of handles to GDI objects
 *    An array of metafile records
 *    A private palette
28 29
 *
 *
30 31 32
 *  The standard format consists of a header and an array of metafile records.
 *
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
33

34 35 36
#include "config.h"
#include "wine/port.h"

37
#include <stdarg.h>
38
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
39
#include <string.h>
40
#include <assert.h>
41
#include "windef.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
42
#include "winbase.h"
43
#include "wingdi.h"
44
#include "winnls.h"
45
#include "winerror.h"
46
#include "gdi_private.h"
47
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
48

49
WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
50

51 52 53 54 55 56 57
typedef struct
{
    GDIOBJHDR      header;
    ENHMETAHEADER  *emh;
    BOOL           on_disk;   /* true if metafile is on disk */
} ENHMETAFILEOBJ;

58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
static const struct emr_name {
    DWORD type;
    const char *name;
} emr_names[] = {
#define X(p) {p, #p}
X(EMR_HEADER),
X(EMR_POLYBEZIER),
X(EMR_POLYGON),
X(EMR_POLYLINE),
X(EMR_POLYBEZIERTO),
X(EMR_POLYLINETO),
X(EMR_POLYPOLYLINE),
X(EMR_POLYPOLYGON),
X(EMR_SETWINDOWEXTEX),
X(EMR_SETWINDOWORGEX),
X(EMR_SETVIEWPORTEXTEX),
X(EMR_SETVIEWPORTORGEX),
X(EMR_SETBRUSHORGEX),
X(EMR_EOF),
X(EMR_SETPIXELV),
X(EMR_SETMAPPERFLAGS),
X(EMR_SETMAPMODE),
X(EMR_SETBKMODE),
X(EMR_SETPOLYFILLMODE),
X(EMR_SETROP2),
X(EMR_SETSTRETCHBLTMODE),
X(EMR_SETTEXTALIGN),
X(EMR_SETCOLORADJUSTMENT),
X(EMR_SETTEXTCOLOR),
X(EMR_SETBKCOLOR),
X(EMR_OFFSETCLIPRGN),
X(EMR_MOVETOEX),
X(EMR_SETMETARGN),
X(EMR_EXCLUDECLIPRECT),
X(EMR_INTERSECTCLIPRECT),
X(EMR_SCALEVIEWPORTEXTEX),
X(EMR_SCALEWINDOWEXTEX),
X(EMR_SAVEDC),
X(EMR_RESTOREDC),
X(EMR_SETWORLDTRANSFORM),
X(EMR_MODIFYWORLDTRANSFORM),
X(EMR_SELECTOBJECT),
X(EMR_CREATEPEN),
X(EMR_CREATEBRUSHINDIRECT),
X(EMR_DELETEOBJECT),
X(EMR_ANGLEARC),
X(EMR_ELLIPSE),
X(EMR_RECTANGLE),
X(EMR_ROUNDRECT),
X(EMR_ARC),
X(EMR_CHORD),
X(EMR_PIE),
X(EMR_SELECTPALETTE),
X(EMR_CREATEPALETTE),
X(EMR_SETPALETTEENTRIES),
X(EMR_RESIZEPALETTE),
X(EMR_REALIZEPALETTE),
X(EMR_EXTFLOODFILL),
X(EMR_LINETO),
X(EMR_ARCTO),
X(EMR_POLYDRAW),
X(EMR_SETARCDIRECTION),
X(EMR_SETMITERLIMIT),
X(EMR_BEGINPATH),
X(EMR_ENDPATH),
X(EMR_CLOSEFIGURE),
X(EMR_FILLPATH),
X(EMR_STROKEANDFILLPATH),
X(EMR_STROKEPATH),
X(EMR_FLATTENPATH),
X(EMR_WIDENPATH),
X(EMR_SELECTCLIPPATH),
X(EMR_ABORTPATH),
X(EMR_GDICOMMENT),
X(EMR_FILLRGN),
X(EMR_FRAMERGN),
X(EMR_INVERTRGN),
X(EMR_PAINTRGN),
X(EMR_EXTSELECTCLIPRGN),
X(EMR_BITBLT),
X(EMR_STRETCHBLT),
X(EMR_MASKBLT),
X(EMR_PLGBLT),
X(EMR_SETDIBITSTODEVICE),
X(EMR_STRETCHDIBITS),
X(EMR_EXTCREATEFONTINDIRECTW),
X(EMR_EXTTEXTOUTA),
X(EMR_EXTTEXTOUTW),
X(EMR_POLYBEZIER16),
X(EMR_POLYGON16),
X(EMR_POLYLINE16),
X(EMR_POLYBEZIERTO16),
X(EMR_POLYLINETO16),
X(EMR_POLYPOLYLINE16),
X(EMR_POLYPOLYGON16),
X(EMR_POLYDRAW16),
X(EMR_CREATEMONOBRUSH),
X(EMR_CREATEDIBPATTERNBRUSHPT),
X(EMR_EXTCREATEPEN),
X(EMR_POLYTEXTOUTA),
X(EMR_POLYTEXTOUTW),
X(EMR_SETICMMODE),
X(EMR_CREATECOLORSPACE),
X(EMR_SETCOLORSPACE),
X(EMR_DELETECOLORSPACE),
X(EMR_GLSRECORD),
X(EMR_GLSBOUNDEDRECORD),
X(EMR_PIXELFORMAT),
X(EMR_DRAWESCAPE),
X(EMR_EXTESCAPE),
X(EMR_STARTDOC),
X(EMR_SMALLTEXTOUT),
X(EMR_FORCEUFIMAPPING),
X(EMR_NAMEDESCAPE),
X(EMR_COLORCORRECTPALETTE),
X(EMR_SETICMPROFILEA),
X(EMR_SETICMPROFILEW),
X(EMR_ALPHABLEND),
X(EMR_SETLAYOUT),
X(EMR_TRANSPARENTBLT),
X(EMR_RESERVED_117),
X(EMR_GRADIENTFILL),
X(EMR_SETLINKEDUFI),
X(EMR_SETTEXTJUSTIFICATION),
X(EMR_COLORMATCHTOTARGETW),
X(EMR_CREATECOLORSPACEW)
#undef X
};

/****************************************************************************
 *         get_emr_name
 */
static const char *get_emr_name(DWORD type)
{
192
    unsigned int i;
193 194
    for(i = 0; i < sizeof(emr_names) / sizeof(emr_names[0]); i++)
        if(type == emr_names[i].type) return emr_names[i].name;
195
    TRACE("Unknown record type %d\n", type);
196 197
   return NULL;
}
198

199 200 201 202 203 204 205 206 207 208 209 210
/***********************************************************************
 *          is_dib_monochrome
 *
 * Returns whether a DIB can be converted to a monochrome DDB.
 *
 * A DIB can be converted if its color table contains only black and
 * white. Black must be the first color in the color table.
 *
 * Note : If the first color in the color table is white followed by
 *        black, we can't convert it to a monochrome DDB with
 *        SetDIBits, because black and white would be inverted.
 */
211
static inline BOOL is_dib_monochrome( const BITMAPINFO* info )
212 213 214 215 216
{
    if (info->bmiHeader.biBitCount != 1) return FALSE;

    if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
    {
217
        const RGBTRIPLE *rgb = ((const BITMAPCOREINFO *) info)->bmciColors;
218

219 220 221 222 223 224 225 226 227 228 229 230
        /* Check if the first color is black */
        if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
        {
            rgb++;
            /* Check if the second color is white */
            return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
                 && (rgb->rgbtBlue == 0xff));
        }
        else return FALSE;
    }
    else  /* assume BITMAPINFOHEADER */
    {
231
        const RGBQUAD *rgb = info->bmiColors;
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246

        /* Check if the first color is black */
        if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
            (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
        {
            rgb++;

            /* Check if the second color is white */
            return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
                 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
        }
        else return FALSE;
    }
}

247 248 249
/****************************************************************************
 *          EMF_Create_HENHMETAFILE
 */
250
HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
251
{
252
    HENHMETAFILE hmf = 0;
253 254 255 256 257 258 259 260 261 262 263 264 265 266
    ENHMETAFILEOBJ *metaObj;

    if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE ||
        (emh->nBytes & 3)) /* refuse to load unaligned EMF as Windows does */
    {
        WARN("Invalid emf header type 0x%08x sig 0x%08x.\n",
             emh->iType, emh->dSignature);
        SetLastError(ERROR_INVALID_DATA);
        return 0;
    }

    metaObj = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
                               ENHMETAFILE_MAGIC,
                               (HGDIOBJ *)&hmf, NULL );
267 268
    if (metaObj)
    {
269 270
        metaObj->emh = emh;
        metaObj->on_disk = on_disk;
271 272
        GDI_ReleaseObj( hmf );
    }
273 274 275 276 277 278 279 280
    return hmf;
}

/****************************************************************************
 *          EMF_Delete_HENHMETAFILE
 */
static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
{
281 282
    ENHMETAFILEOBJ *metaObj = GDI_GetObjPtr( hmf, ENHMETAFILE_MAGIC );

283
    if(!metaObj) return FALSE;
284 285

    if(metaObj->on_disk)
286
        UnmapViewOfFile( metaObj->emh );
287
    else
288
        HeapFree( GetProcessHeap(), 0, metaObj->emh );
289
    return GDI_FreeObject( hmf, metaObj );
290 291 292 293 294 295 296 297 298
}

/******************************************************************
 *         EMF_GetEnhMetaHeader
 *
 * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
 */
static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
{
299
    ENHMETAHEADER *ret = NULL;
300
    ENHMETAFILEOBJ *metaObj = GDI_GetObjPtr( hmf, ENHMETAFILE_MAGIC );
301
    TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj);
302 303 304 305 306 307
    if (metaObj)
    {
        ret = metaObj->emh;
        GDI_ReleaseObj( hmf );
    }
    return ret;
308
}
309

Alexandre Julliard's avatar
Alexandre Julliard committed
310
/*****************************************************************************
311 312 313
 *         EMF_GetEnhMetaFile
 *
 */
314
static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
315 316 317
{
    ENHMETAHEADER *emh;
    HANDLE hMapping;
318
    HENHMETAFILE hemf;
319

320 321
    hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
    emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
322 323 324
    CloseHandle( hMapping );

    if (!emh) return 0;
325

326 327 328 329
    hemf = EMF_Create_HENHMETAFILE( emh, TRUE );
    if (!hemf)
        UnmapViewOfFile( emh );
    return hemf;
330 331 332 333
}


/*****************************************************************************
334
 *          GetEnhMetaFileA (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
335 336 337
 *
 *
 */
338
HENHMETAFILE WINAPI GetEnhMetaFileA(
339
	     LPCSTR lpszMetaFile  /* [in] filename of enhanced metafile */
Alexandre Julliard's avatar
Alexandre Julliard committed
340 341
    )
{
342
    HENHMETAFILE hmf;
343
    HANDLE hFile;
344

345 346
    hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
			OPEN_EXISTING, 0, 0);
347
    if (hFile == INVALID_HANDLE_VALUE) {
348
        WARN("could not open %s\n", lpszMetaFile);
349 350 351
	return 0;
    }
    hmf = EMF_GetEnhMetaFile( hFile );
352
    CloseHandle( hFile );
353
    return hmf;
Alexandre Julliard's avatar
Alexandre Julliard committed
354 355
}

356
/*****************************************************************************
357
 *          GetEnhMetaFileW  (GDI32.@)
358
 */
359
HENHMETAFILE WINAPI GetEnhMetaFileW(
360
             LPCWSTR lpszMetaFile)  /* [in] filename of enhanced metafile */
361
{
362
    HENHMETAFILE hmf;
363
    HANDLE hFile;
364

365 366
    hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
			OPEN_EXISTING, 0, 0);
367
    if (hFile == INVALID_HANDLE_VALUE) {
368
        WARN("could not open %s\n", debugstr_w(lpszMetaFile));
369 370 371
	return 0;
    }
    hmf = EMF_GetEnhMetaFile( hFile );
372
    CloseHandle( hFile );
373
    return hmf;
374 375
}

Alexandre Julliard's avatar
Alexandre Julliard committed
376
/*****************************************************************************
377
 *        GetEnhMetaFileHeader  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
378
 *
379 380 381 382
 * Retrieves the record containing the header for the specified
 * enhanced-format metafile.
 *
 * RETURNS
383
 *  If buf is NULL, returns the size of buffer required.
384
 *  Otherwise, copy up to bufsize bytes of enhanced metafile header into
385
 *  buf.
Alexandre Julliard's avatar
Alexandre Julliard committed
386
 */
387
UINT WINAPI GetEnhMetaFileHeader(
388 389
       HENHMETAFILE hmf,   /* [in] enhanced metafile */
       UINT bufsize,       /* [in] size of buffer */
390
       LPENHMETAHEADER buf /* [out] buffer */
Alexandre Julliard's avatar
Alexandre Julliard committed
391 392
    )
{
393
    LPENHMETAHEADER emh;
394
    UINT size;
395 396

    emh = EMF_GetEnhMetaHeader(hmf);
397
    if(!emh) return FALSE;
398
    size = emh->nSize;
399
    if (!buf) return size;
400 401 402
    size = min(size, bufsize);
    memmove(buf, emh, size);
    return size;
Alexandre Julliard's avatar
Alexandre Julliard committed
403 404 405 406
}


/*****************************************************************************
407
 *          GetEnhMetaFileDescriptionA  (GDI32.@)
408 409
 *
 * See GetEnhMetaFileDescriptionW.
Alexandre Julliard's avatar
Alexandre Julliard committed
410
 */
411
UINT WINAPI GetEnhMetaFileDescriptionA(
412
       HENHMETAFILE hmf, /* [in] enhanced metafile */
413
       UINT size,        /* [in] size of buf */
414
       LPSTR buf         /* [out] buffer to receive description */
Alexandre Julliard's avatar
Alexandre Julliard committed
415 416
    )
{
417
     LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
418 419 420
     DWORD len;
     WCHAR *descrW;

421
     if(!emh) return FALSE;
422
     if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
423 424 425
     descrW = (WCHAR *) ((char *) emh + emh->offDescription);
     len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL );

426
     if (!buf || !size ) return len;
427 428 429 430

     len = min( size, len );
     WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL );
     return len;
Alexandre Julliard's avatar
Alexandre Julliard committed
431 432 433
}

/*****************************************************************************
434
 *          GetEnhMetaFileDescriptionW  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
435
 *
436
 *  Copies the description string of an enhanced metafile into a buffer
Alexandre Julliard's avatar
Alexandre Julliard committed
437 438
 *  _buf_.
 *
439
 * RETURNS
Alexandre Julliard's avatar
Alexandre Julliard committed
440 441
 *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
 *  number of characters copied.
Alexandre Julliard's avatar
Alexandre Julliard committed
442
 */
443
UINT WINAPI GetEnhMetaFileDescriptionW(
444
       HENHMETAFILE hmf, /* [in] enhanced metafile */
445
       UINT size,        /* [in] size of buf */
446
       LPWSTR buf        /* [out] buffer to receive description */
Alexandre Julliard's avatar
Alexandre Julliard committed
447 448
    )
{
449
     LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
450 451

     if(!emh) return FALSE;
452 453 454 455
     if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
     if (!buf || !size ) return emh->nDescription;

     memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR));
456
     return min(size, emh->nDescription);
Alexandre Julliard's avatar
Alexandre Julliard committed
457 458
}

Alexandre Julliard's avatar
Alexandre Julliard committed
459
/****************************************************************************
460
 *    SetEnhMetaFileBits (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
461 462 463
 *
 *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
 */
464
HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
Alexandre Julliard's avatar
Alexandre Julliard committed
465
{
466
    ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
467
    memmove(emh, buf, bufsize);
468
    return EMF_Create_HENHMETAFILE( emh, FALSE );
Alexandre Julliard's avatar
Alexandre Julliard committed
469 470 471
}

/*****************************************************************************
472
 *  GetEnhMetaFileBits (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
473 474
 *
 */
475
UINT WINAPI GetEnhMetaFileBits(
476 477 478 479
    HENHMETAFILE hmf,
    UINT bufsize,
    LPBYTE buf
)
480
{
481 482
    LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf );
    UINT size;
483

484
    if(!emh) return 0;
485

486
    size = emh->nBytes;
487
    if( buf == NULL ) return size;
488

489 490 491
    size = min( size, bufsize );
    memmove(buf, emh, size);
    return size;
Alexandre Julliard's avatar
Alexandre Julliard committed
492 493
}

494
typedef struct EMF_dc_state
495 496 497 498 499 500 501 502 503 504 505
{
    INT   mode;
    XFORM world_transform;
    INT   wndOrgX;
    INT   wndOrgY;
    INT   wndExtX;
    INT   wndExtY;
    INT   vportOrgX;
    INT   vportOrgY;
    INT   vportExtX;
    INT   vportExtY;
506 507 508 509 510 511 512 513 514
    struct EMF_dc_state *next;
} EMF_dc_state;

typedef struct enum_emh_data
{
    XFORM init_transform;
    EMF_dc_state state;
    INT save_level;
    EMF_dc_state *saved_state;
515 516 517 518 519 520 521 522 523 524
} enum_emh_data;

#define ENUM_GET_PRIVATE_DATA(ht) \
    ((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data)))

#define WIDTH(rect) ( (rect).right - (rect).left )
#define HEIGHT(rect) ( (rect).bottom - (rect).top )

#define IS_WIN9X() (GetVersion()&0x80000000)

525
static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info)
526 527
{
    XFORM mapping_mode_trans, final_trans;
528
    double scaleX, scaleY;
529

530 531
    scaleX = (double)info->state.vportExtX / (double)info->state.wndExtX;
    scaleY = (double)info->state.vportExtY / (double)info->state.wndExtY;
532 533 534 535
    mapping_mode_trans.eM11 = scaleX;
    mapping_mode_trans.eM12 = 0.0;
    mapping_mode_trans.eM21 = 0.0;
    mapping_mode_trans.eM22 = scaleY;
536 537
    mapping_mode_trans.eDx  = (double)info->state.vportOrgX - scaleX * (double)info->state.wndOrgX;
    mapping_mode_trans.eDy  = (double)info->state.vportOrgY - scaleY * (double)info->state.wndOrgY;
538

539
    CombineTransform(&final_trans, &info->state.world_transform, &mapping_mode_trans);
540 541 542 543 544 545 546 547
    CombineTransform(&final_trans, &final_trans, &info->init_transform);
 
    if (!SetWorldTransform(hdc, &final_trans))
    {
        ERR("World transform failed!\n");
    }
}

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577
static void EMF_RestoreDC( enum_emh_data *info, INT level )
{
    if (abs(level) > info->save_level || level == 0) return;

    if (level < 0) level = info->save_level + level + 1;

    while (info->save_level >= level)
    {
        EMF_dc_state *state = info->saved_state;
        info->saved_state = state->next;
        state->next = NULL;
        if (--info->save_level < level)
            info->state = *state;
        HeapFree( GetProcessHeap(), 0, state );
    }
}

static void EMF_SaveDC( enum_emh_data *info )
{
    EMF_dc_state *state = HeapAlloc( GetProcessHeap(), 0, sizeof(*state));
    if (state)
    {
        *state = info->state;
        state->next = info->saved_state;
        info->saved_state = state;
        info->save_level++;
        TRACE("save_level %d\n", info->save_level);
    }
}

578
static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
579 580 581 582 583 584
{
    INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
    INT vertSize = GetDeviceCaps( hdc, VERTSIZE );
    INT horzRes  = GetDeviceCaps( hdc, HORZRES );
    INT vertRes  = GetDeviceCaps( hdc, VERTRES );

585
    TRACE("%d\n", info->state.mode);
586

587
    switch(info->state.mode)
588 589
    {
    case MM_TEXT:
590 591 592 593
        info->state.wndExtX   = 1;
        info->state.wndExtY   = 1;
        info->state.vportExtX = 1;
        info->state.vportExtY = 1;
594 595 596
        break;
    case MM_LOMETRIC:
    case MM_ISOTROPIC:
597 598 599 600
        info->state.wndExtX   = horzSize * 10;
        info->state.wndExtY   = vertSize * 10;
        info->state.vportExtX = horzRes;
        info->state.vportExtY = -vertRes;
601 602
        break;
    case MM_HIMETRIC:
603 604 605 606
        info->state.wndExtX   = horzSize * 100;
        info->state.wndExtY   = vertSize * 100;
        info->state.vportExtX = horzRes;
        info->state.vportExtY = -vertRes;
607 608
        break;
    case MM_LOENGLISH:
609 610 611 612
        info->state.wndExtX   = MulDiv(1000, horzSize, 254);
        info->state.wndExtY   = MulDiv(1000, vertSize, 254);
        info->state.vportExtX = horzRes;
        info->state.vportExtY = -vertRes;
613 614
        break;
    case MM_HIENGLISH:
615 616 617 618
        info->state.wndExtX   = MulDiv(10000, horzSize, 254);
        info->state.wndExtY   = MulDiv(10000, vertSize, 254);
        info->state.vportExtX = horzRes;
        info->state.vportExtY = -vertRes;
619 620
        break;
    case MM_TWIPS:
621 622 623 624
        info->state.wndExtX   = MulDiv(14400, horzSize, 254);
        info->state.wndExtY   = MulDiv(14400, vertSize, 254);
        info->state.vportExtX = horzRes;
        info->state.vportExtY = -vertRes;
625 626 627 628 629 630 631 632
        break;
    case MM_ANISOTROPIC:
        break;
    default:
        return;
    }
}

633 634 635 636 637 638 639 640
/***********************************************************************
 *           EMF_FixIsotropic
 *
 * Fix viewport extensions for isotropic mode.
 */

static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info)
{
641 642 643 644
    double xdim = fabs((double)info->state.vportExtX * GetDeviceCaps( hdc, HORZSIZE ) /
                  (GetDeviceCaps( hdc, HORZRES ) * info->state.wndExtX));
    double ydim = fabs((double)info->state.vportExtY * GetDeviceCaps( hdc, VERTSIZE ) /
                  (GetDeviceCaps( hdc, VERTRES ) * info->state.wndExtY));
645 646 647

    if (xdim > ydim)
    {
648 649 650
        INT mincx = (info->state.vportExtX >= 0) ? 1 : -1;
        info->state.vportExtX = floor(info->state.vportExtX * ydim / xdim + 0.5);
        if (!info->state.vportExtX) info->state.vportExtX = mincx;
651 652 653
    }
    else
    {
654 655 656
        INT mincy = (info->state.vportExtY >= 0) ? 1 : -1;
        info->state.vportExtY = floor(info->state.vportExtY * xdim / ydim + 0.5);
        if (!info->state.vportExtY) info->state.vportExtY = mincy;
657 658 659
    }
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694
/*****************************************************************************
 *       emr_produces_output
 *
 * Returns TRUE if the record type writes something to the dc.  Used by
 * PlayEnhMetaFileRecord to determine whether it needs to update the
 * dc's xform when in win9x mode.
 *
 * FIXME: need to test which records should be here.
 */
static BOOL emr_produces_output(int type)
{
    switch(type) {
    case EMR_POLYBEZIER:
    case EMR_POLYGON:
    case EMR_POLYLINE:
    case EMR_POLYBEZIERTO:
    case EMR_POLYLINETO:
    case EMR_POLYPOLYLINE:
    case EMR_POLYPOLYGON:
    case EMR_SETPIXELV:
    case EMR_MOVETOEX:
    case EMR_EXCLUDECLIPRECT:
    case EMR_INTERSECTCLIPRECT:
    case EMR_SELECTOBJECT:
    case EMR_ANGLEARC:
    case EMR_ELLIPSE:
    case EMR_RECTANGLE:
    case EMR_ROUNDRECT:
    case EMR_ARC:
    case EMR_CHORD:
    case EMR_PIE:
    case EMR_EXTFLOODFILL:
    case EMR_LINETO:
    case EMR_ARCTO:
    case EMR_POLYDRAW:
695
    case EMR_GDICOMMENT:
696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
    case EMR_FILLRGN:
    case EMR_FRAMERGN:
    case EMR_INVERTRGN:
    case EMR_PAINTRGN:
    case EMR_BITBLT:
    case EMR_STRETCHBLT:
    case EMR_MASKBLT:
    case EMR_PLGBLT:
    case EMR_SETDIBITSTODEVICE:
    case EMR_STRETCHDIBITS:
    case EMR_EXTTEXTOUTA:
    case EMR_EXTTEXTOUTW:
    case EMR_POLYBEZIER16:
    case EMR_POLYGON16:
    case EMR_POLYLINE16:
    case EMR_POLYBEZIERTO16:
    case EMR_POLYLINETO16:
    case EMR_POLYPOLYLINE16:
    case EMR_POLYPOLYGON16:
    case EMR_POLYDRAW16:
    case EMR_POLYTEXTOUTA:
    case EMR_POLYTEXTOUTW:
    case EMR_SMALLTEXTOUT:
719
    case EMR_ALPHABLEND:
720 721 722 723 724 725 726 727
    case EMR_TRANSPARENTBLT:
        return TRUE;
    default:
        return FALSE;
    }
}


Alexandre Julliard's avatar
Alexandre Julliard committed
728
/*****************************************************************************
729
 *           PlayEnhMetaFileRecord  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
730 731 732 733
 *
 *  Render a single enhanced metafile record in the device context hdc.
 *
 *  RETURNS
734
 *    TRUE (non zero) on success, FALSE on error.
Alexandre Julliard's avatar
Alexandre Julliard committed
735
 *  BUGS
Alexandre Julliard's avatar
Alexandre Julliard committed
736
 *    Many unimplemented records.
737
 *    No error handling on record play failures (ie checking return codes)
738 739 740 741
 *
 * NOTES
 *    WinNT actually updates the current world transform in this function
 *     whereas Win9x does not.
Alexandre Julliard's avatar
Alexandre Julliard committed
742
 */
743
BOOL WINAPI PlayEnhMetaFileRecord(
744 745 746 747
     HDC hdc,                   /* [in] device context in which to render EMF record */
     LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */
     const ENHMETARECORD *mr,   /* [in] EMF record to render */
     UINT handles               /* [in] size of handle array */
748
     )
Alexandre Julliard's avatar
Alexandre Julliard committed
749 750
{
  int type;
751 752
  RECT tmprc;
  enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
753

754 755
  TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n",
        hdc, handletable, mr, handles);
Alexandre Julliard's avatar
Alexandre Julliard committed
756
  if (!mr) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
757

Alexandre Julliard's avatar
Alexandre Julliard committed
758
  type = mr->iType;
Alexandre Julliard's avatar
Alexandre Julliard committed
759

760
  TRACE("record %s\n", get_emr_name(type));
761
  switch(type)
Alexandre Julliard's avatar
Alexandre Julliard committed
762 763
    {
    case EMR_HEADER:
764
      break;
Alexandre Julliard's avatar
Alexandre Julliard committed
765
    case EMR_EOF:
Alexandre Julliard's avatar
Alexandre Julliard committed
766 767
      break;
    case EMR_GDICOMMENT:
768
      {
769
        const EMRGDICOMMENT *lpGdiComment = (const EMRGDICOMMENT *)mr;
770 771 772
        /* In an enhanced metafile, there can be both public and private GDI comments */
        GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
        break;
773
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
774 775
    case EMR_SETMAPMODE:
      {
776
        const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr;
777

778 779
        if (info->state.mode == pSetMapMode->iMode &&
            (info->state.mode == MM_ISOTROPIC || info->state.mode == MM_ANISOTROPIC))
780
            break;
781
        info->state.mode = pSetMapMode->iMode;
782
        EMF_SetMapMode(hdc, info);
Alexandre Julliard's avatar
Alexandre Julliard committed
783 784 785 786
	break;
      }
    case EMR_SETBKMODE:
      {
787
        const EMRSETBKMODE *pSetBkMode = (const EMRSETBKMODE *)mr;
788
	SetBkMode(hdc, pSetBkMode->iMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
789 790 791 792
	break;
      }
    case EMR_SETBKCOLOR:
      {
793
        const EMRSETBKCOLOR *pSetBkColor = (const EMRSETBKCOLOR *)mr;
794
	SetBkColor(hdc, pSetBkColor->crColor);
Alexandre Julliard's avatar
Alexandre Julliard committed
795 796 797 798
	break;
      }
    case EMR_SETPOLYFILLMODE:
      {
799
        const EMRSETPOLYFILLMODE *pSetPolyFillMode = (const EMRSETPOLYFILLMODE *)mr;
800
	SetPolyFillMode(hdc, pSetPolyFillMode->iMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
801 802 803 804
	break;
      }
    case EMR_SETROP2:
      {
805
        const EMRSETROP2 *pSetROP2 = (const EMRSETROP2 *)mr;
806
	SetROP2(hdc, pSetROP2->iMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
807 808 809 810
	break;
      }
    case EMR_SETSTRETCHBLTMODE:
      {
811
	const EMRSETSTRETCHBLTMODE *pSetStretchBltMode = (const EMRSETSTRETCHBLTMODE *)mr;
812
	SetStretchBltMode(hdc, pSetStretchBltMode->iMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
813 814 815 816
	break;
      }
    case EMR_SETTEXTALIGN:
      {
817
	const EMRSETTEXTALIGN *pSetTextAlign = (const EMRSETTEXTALIGN *)mr;
818
	SetTextAlign(hdc, pSetTextAlign->iMode);
Alexandre Julliard's avatar
Alexandre Julliard committed
819 820 821 822
	break;
      }
    case EMR_SETTEXTCOLOR:
      {
823
	const EMRSETTEXTCOLOR *pSetTextColor = (const EMRSETTEXTCOLOR *)mr;
824
	SetTextColor(hdc, pSetTextColor->crColor);
Alexandre Julliard's avatar
Alexandre Julliard committed
825 826 827 828
	break;
      }
    case EMR_SAVEDC:
      {
829 830
        if (SaveDC( hdc ))
            EMF_SaveDC( info );
Alexandre Julliard's avatar
Alexandre Julliard committed
831 832 833 834
	break;
      }
    case EMR_RESTOREDC:
      {
835
	const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr;
836
        TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative);
837 838
        if (RestoreDC( hdc, pRestoreDC->iRelative ))
            EMF_RestoreDC( info, pRestoreDC->iRelative );
Alexandre Julliard's avatar
Alexandre Julliard committed
839 840 841 842
	break;
      }
    case EMR_INTERSECTCLIPRECT:
      {
843
	const EMRINTERSECTCLIPRECT *pClipRect = (const EMRINTERSECTCLIPRECT *)mr;
844
        TRACE("EMR_INTERSECTCLIPRECT: rect %d,%d - %d, %d\n",
845 846 847 848
              pClipRect->rclClip.left, pClipRect->rclClip.top,
              pClipRect->rclClip.right, pClipRect->rclClip.bottom);
        IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top,
                          pClipRect->rclClip.right, pClipRect->rclClip.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
849 850 851 852
	break;
      }
    case EMR_SELECTOBJECT:
      {
853
	const EMRSELECTOBJECT *pSelectObject = (const EMRSELECTOBJECT *)mr;
854 855 856 857 858 859 860 861 862 863 864 865 866
	if( pSelectObject->ihObject & 0x80000000 ) {
	  /* High order bit is set - it's a stock object
	   * Strip the high bit to get the index.
	   * See MSDN article Q142319
	   */
	  SelectObject( hdc, GetStockObject( pSelectObject->ihObject &
					     0x7fffffff ) );
	} else {
	  /* High order bit wasn't set - not a stock object
	   */
	      SelectObject( hdc,
			(handletable->objectHandle)[pSelectObject->ihObject] );
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
867 868 869 870
	break;
      }
    case EMR_DELETEOBJECT:
      {
871
	const EMRDELETEOBJECT *pDeleteObject = (const EMRDELETEOBJECT *)mr;
872 873
	DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]);
	(handletable->objectHandle)[pDeleteObject->ihObject] = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
874 875 876 877
	break;
      }
    case EMR_SETWINDOWORGEX:
      {
878
    	const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr;
879

880 881
        info->state.wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
        info->state.wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
882

883
        TRACE("SetWindowOrgEx: %d,%d\n", info->state.wndOrgX, info->state.wndOrgY);
884
        break;
Alexandre Julliard's avatar
Alexandre Julliard committed
885 886 887
      }
    case EMR_SETWINDOWEXTEX:
      {
888
	const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr;
889
	
890
        if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
891
	    break;
892 893 894
        info->state.wndExtX = pSetWindowExtEx->szlExtent.cx;
        info->state.wndExtY = pSetWindowExtEx->szlExtent.cy;
        if (info->state.mode == MM_ISOTROPIC)
895
            EMF_FixIsotropic(hdc, info);
896

897
        TRACE("SetWindowExtEx: %d,%d\n",info->state.wndExtX, info->state.wndExtY);
Alexandre Julliard's avatar
Alexandre Julliard committed
898 899 900 901
	break;
      }
    case EMR_SETVIEWPORTORGEX:
      {
902
	const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr;
903

904 905 906
        info->state.vportOrgX = pSetViewportOrgEx->ptlOrigin.x;
        info->state.vportOrgY = pSetViewportOrgEx->ptlOrigin.y;
        TRACE("SetViewportOrgEx: %d,%d\n", info->state.vportOrgX, info->state.vportOrgY);
Alexandre Julliard's avatar
Alexandre Julliard committed
907 908 909 910
	break;
      }
    case EMR_SETVIEWPORTEXTEX:
      {
911
	const EMRSETVIEWPORTEXTEX *pSetViewportExtEx = (const EMRSETVIEWPORTEXTEX *)mr;
912

913
        if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
914
	    break;
915 916 917
        info->state.vportExtX = pSetViewportExtEx->szlExtent.cx;
        info->state.vportExtY = pSetViewportExtEx->szlExtent.cy;
        if (info->state.mode == MM_ISOTROPIC)
918
            EMF_FixIsotropic(hdc, info);
919
        TRACE("SetViewportExtEx: %d,%d\n", info->state.vportExtX, info->state.vportExtY);
Alexandre Julliard's avatar
Alexandre Julliard committed
920 921 922 923
	break;
      }
    case EMR_CREATEPEN:
      {
924
	const EMRCREATEPEN *pCreatePen = (const EMRCREATEPEN *)mr;
925
	(handletable->objectHandle)[pCreatePen->ihPen] =
926
	  CreatePenIndirect(&pCreatePen->lopn);
Alexandre Julliard's avatar
Alexandre Julliard committed
927 928 929 930
	break;
      }
    case EMR_EXTCREATEPEN:
      {
931
	const EMREXTCREATEPEN *pPen = (const EMREXTCREATEPEN *)mr;
932 933 934 935 936 937 938 939
	LOGBRUSH lb;
	lb.lbStyle = pPen->elp.elpBrushStyle;
	lb.lbColor = pPen->elp.elpColor;
	lb.lbHatch = pPen->elp.elpHatch;

	if(pPen->offBmi || pPen->offBits)
	  FIXME("EMR_EXTCREATEPEN: Need to copy brush bitmap\n");

940 941
	(handletable->objectHandle)[pPen->ihPen] =
	  ExtCreatePen(pPen->elp.elpPenStyle, pPen->elp.elpWidth, &lb,
942
		       pPen->elp.elpNumEntries, pPen->elp.elpStyleEntry);
Alexandre Julliard's avatar
Alexandre Julliard committed
943 944 945 946
	break;
      }
    case EMR_CREATEBRUSHINDIRECT:
      {
947
	const EMRCREATEBRUSHINDIRECT *pBrush = (const EMRCREATEBRUSHINDIRECT *)mr;
948 949 950 951 952
        LOGBRUSH brush;
        brush.lbStyle = pBrush->lb.lbStyle;
        brush.lbColor = pBrush->lb.lbColor;
        brush.lbHatch = pBrush->lb.lbHatch;
        (handletable->objectHandle)[pBrush->ihBrush] = CreateBrushIndirect(&brush);
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954 955
	break;
      }
    case EMR_EXTCREATEFONTINDIRECTW:
956
      {
957
	const EMREXTCREATEFONTINDIRECTW *pFont = (const EMREXTCREATEFONTINDIRECTW *)mr;
958
	(handletable->objectHandle)[pFont->ihFont] =
959
	  CreateFontIndirectW(&pFont->elfw.elfLogFont);
Alexandre Julliard's avatar
Alexandre Julliard committed
960
	break;
961
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
962 963
    case EMR_MOVETOEX:
      {
964
	const EMRMOVETOEX *pMoveToEx = (const EMRMOVETOEX *)mr;
965
	MoveToEx(hdc, pMoveToEx->ptl.x, pMoveToEx->ptl.y, NULL);
Alexandre Julliard's avatar
Alexandre Julliard committed
966 967 968 969
	break;
      }
    case EMR_LINETO:
      {
970
	const EMRLINETO *pLineTo = (const EMRLINETO *)mr;
971
        LineTo(hdc, pLineTo->ptl.x, pLineTo->ptl.y);
Alexandre Julliard's avatar
Alexandre Julliard committed
972 973 974 975
	break;
      }
    case EMR_RECTANGLE:
      {
976
	const EMRRECTANGLE *pRect = (const EMRRECTANGLE *)mr;
977 978
	Rectangle(hdc, pRect->rclBox.left, pRect->rclBox.top,
		  pRect->rclBox.right, pRect->rclBox.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
979 980 981 982
	break;
      }
    case EMR_ELLIPSE:
      {
983
	const EMRELLIPSE *pEllipse = (const EMRELLIPSE *)mr;
984 985
	Ellipse(hdc, pEllipse->rclBox.left, pEllipse->rclBox.top,
		pEllipse->rclBox.right, pEllipse->rclBox.bottom);
Alexandre Julliard's avatar
Alexandre Julliard committed
986 987 988 989
	break;
      }
    case EMR_POLYGON16:
      {
990
	const EMRPOLYGON16 *pPoly = (const EMRPOLYGON16 *)mr;
991 992 993 994 995
	/* Shouldn't use Polygon16 since pPoly->cpts is DWORD */
	POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				pPoly->cpts * sizeof(POINT) );
	DWORD i;
	for(i = 0; i < pPoly->cpts; i++)
996 997 998 999
	{
	    pts[i].x = pPoly->apts[i].x;
	    pts[i].y = pPoly->apts[i].y;
	}
1000 1001
	Polygon(hdc, pts, pPoly->cpts);
	HeapFree( GetProcessHeap(), 0, pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
1002 1003
	break;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1004 1005
    case EMR_POLYLINE16:
      {
1006
	const EMRPOLYLINE16 *pPoly = (const EMRPOLYLINE16 *)mr;
1007 1008 1009 1010 1011
	/* Shouldn't use Polyline16 since pPoly->cpts is DWORD */
	POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				pPoly->cpts * sizeof(POINT) );
	DWORD i;
	for(i = 0; i < pPoly->cpts; i++)
1012 1013 1014 1015
	{
	    pts[i].x = pPoly->apts[i].x;
	    pts[i].y = pPoly->apts[i].y;
	}
1016 1017
	Polyline(hdc, pts, pPoly->cpts);
	HeapFree( GetProcessHeap(), 0, pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
1018 1019
	break;
      }
1020 1021
    case EMR_POLYLINETO16:
      {
1022
	const EMRPOLYLINETO16 *pPoly = (const EMRPOLYLINETO16 *)mr;
1023 1024 1025 1026 1027
	/* Shouldn't use PolylineTo16 since pPoly->cpts is DWORD */
	POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				pPoly->cpts * sizeof(POINT) );
	DWORD i;
	for(i = 0; i < pPoly->cpts; i++)
1028 1029 1030 1031
	{
	    pts[i].x = pPoly->apts[i].x;
	    pts[i].y = pPoly->apts[i].y;
	}
1032 1033 1034 1035 1036 1037
	PolylineTo(hdc, pts, pPoly->cpts);
	HeapFree( GetProcessHeap(), 0, pts );
	break;
      }
    case EMR_POLYBEZIER16:
      {
1038
	const EMRPOLYBEZIER16 *pPoly = (const EMRPOLYBEZIER16 *)mr;
1039 1040 1041 1042 1043
	/* Shouldn't use PolyBezier16 since pPoly->cpts is DWORD */
	POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				pPoly->cpts * sizeof(POINT) );
	DWORD i;
	for(i = 0; i < pPoly->cpts; i++)
1044 1045 1046 1047
	{
	    pts[i].x = pPoly->apts[i].x;
	    pts[i].y = pPoly->apts[i].y;
	}
1048 1049 1050 1051 1052 1053
	PolyBezier(hdc, pts, pPoly->cpts);
	HeapFree( GetProcessHeap(), 0, pts );
	break;
      }
    case EMR_POLYBEZIERTO16:
      {
1054
	const EMRPOLYBEZIERTO16 *pPoly = (const EMRPOLYBEZIERTO16 *)mr;
1055 1056 1057 1058 1059
	/* Shouldn't use PolyBezierTo16 since pPoly->cpts is DWORD */
	POINT *pts = HeapAlloc( GetProcessHeap(), 0,
				pPoly->cpts * sizeof(POINT) );
	DWORD i;
	for(i = 0; i < pPoly->cpts; i++)
1060 1061 1062 1063
	{
	    pts[i].x = pPoly->apts[i].x;
	    pts[i].y = pPoly->apts[i].y;
	}
1064 1065 1066 1067
	PolyBezierTo(hdc, pts, pPoly->cpts);
	HeapFree( GetProcessHeap(), 0, pts );
	break;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1068 1069
    case EMR_POLYPOLYGON16:
      {
1070
        const EMRPOLYPOLYGON16 *pPolyPoly = (const EMRPOLYPOLYGON16 *)mr;
1071 1072
	/* NB POINTS array doesn't start at pPolyPoly->apts it's actually
	   pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
1073

1074 1075
        POINT16 *pts16 = (POINT16 *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys);
        POINT *pts = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) );
1076 1077
	DWORD i;
	for(i = 0; i < pPolyPoly->cpts; i++)
1078 1079 1080 1081
        {
            pts[i].x = pts16[i].x;
            pts[i].y = pts16[i].y;
        }
1082 1083
	PolyPolygon(hdc, pts, (INT*)pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
	HeapFree( GetProcessHeap(), 0, pts );
Alexandre Julliard's avatar
Alexandre Julliard committed
1084 1085
	break;
      }
1086 1087
    case EMR_POLYPOLYLINE16:
      {
1088
        const EMRPOLYPOLYLINE16 *pPolyPoly = (const EMRPOLYPOLYLINE16 *)mr;
1089 1090 1091
	/* NB POINTS array doesn't start at pPolyPoly->apts it's actually
	   pPolyPoly->aPolyCounts + pPolyPoly->nPolys */

1092 1093
        POINT16 *pts16 = (POINT16 *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys);
        POINT *pts = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) );
1094 1095
	DWORD i;
	for(i = 0; i < pPolyPoly->cpts; i++)
1096 1097 1098 1099
        {
            pts[i].x = pts16[i].x;
            pts[i].y = pts16[i].y;
        }
1100 1101 1102 1103
	PolyPolyline(hdc, pts, pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
	HeapFree( GetProcessHeap(), 0, pts );
	break;
      }
1104

1105 1106
    case EMR_STRETCHDIBITS:
      {
1107
	const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)mr;
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117

	StretchDIBits(hdc,
		      pStretchDIBits->xDest,
		      pStretchDIBits->yDest,
		      pStretchDIBits->cxDest,
		      pStretchDIBits->cyDest,
		      pStretchDIBits->xSrc,
		      pStretchDIBits->ySrc,
		      pStretchDIBits->cxSrc,
		      pStretchDIBits->cySrc,
1118 1119
		      (const BYTE *)mr + pStretchDIBits->offBitsSrc,
		      (const BITMAPINFO *)((const BYTE *)mr + pStretchDIBits->offBmiSrc),
1120 1121
		      pStretchDIBits->iUsageSrc,
		      pStretchDIBits->dwRop);
1122
	break;
1123
      }
1124 1125 1126

    case EMR_EXTTEXTOUTA:
    {
1127
	const EMREXTTEXTOUTA *pExtTextOutA = (const EMREXTTEXTOUTA *)mr;
1128
	RECT rc;
1129
        const INT *dx = NULL;
1130 1131 1132 1133 1134

	rc.left = pExtTextOutA->emrtext.rcl.left;
	rc.top = pExtTextOutA->emrtext.rcl.top;
	rc.right = pExtTextOutA->emrtext.rcl.right;
	rc.bottom = pExtTextOutA->emrtext.rcl.bottom;
1135
        TRACE("EMR_EXTTEXTOUTA: x,y = %d, %d. rect = %d, %d - %d, %d. flags %08x\n",
1136 1137 1138 1139 1140 1141 1142 1143
              pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
              rc.left, rc.top, rc.right, rc.bottom, pExtTextOutA->emrtext.fOptions);

        /* Linux version of pstoedit produces EMFs with offDx set to 0.
         * These files can be enumerated and played under Win98 just
         * fine, but at least Win2k chokes on them.
         */
        if (pExtTextOutA->emrtext.offDx)
1144
            dx = (const INT *)((const BYTE *)mr + pExtTextOutA->emrtext.offDx);
1145

1146 1147
	ExtTextOutA(hdc, pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
	    pExtTextOutA->emrtext.fOptions, &rc,
1148
	    (LPCSTR)((const BYTE *)mr + pExtTextOutA->emrtext.offString), pExtTextOutA->emrtext.nChars,
1149
	    dx);
1150 1151 1152
	break;
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
1153
    case EMR_EXTTEXTOUTW:
1154
    {
1155
	const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)mr;
1156
	RECT rc;
1157
        const INT *dx = NULL;
1158 1159 1160 1161 1162

	rc.left = pExtTextOutW->emrtext.rcl.left;
	rc.top = pExtTextOutW->emrtext.rcl.top;
	rc.right = pExtTextOutW->emrtext.rcl.right;
	rc.bottom = pExtTextOutW->emrtext.rcl.bottom;
1163
        TRACE("EMR_EXTTEXTOUTW: x,y = %d, %d.  rect = %d, %d - %d, %d. flags %08x\n",
1164 1165 1166
              pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
              rc.left, rc.top, rc.right, rc.bottom, pExtTextOutW->emrtext.fOptions);

1167 1168 1169 1170 1171
        /* Linux version of pstoedit produces EMFs with offDx set to 0.
         * These files can be enumerated and played under Win98 just
         * fine, but at least Win2k chokes on them.
         */
        if (pExtTextOutW->emrtext.offDx)
1172
            dx = (const INT *)((const BYTE *)mr + pExtTextOutW->emrtext.offDx);
1173

1174 1175
	ExtTextOutW(hdc, pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
	    pExtTextOutW->emrtext.fOptions, &rc,
1176
	    (LPCWSTR)((const BYTE *)mr + pExtTextOutW->emrtext.offString), pExtTextOutW->emrtext.nChars,
1177
	    dx);
Alexandre Julliard's avatar
Alexandre Julliard committed
1178
	break;
1179 1180
    }

1181 1182
    case EMR_CREATEPALETTE:
      {
1183
	const EMRCREATEPALETTE *lpCreatePal = (const EMRCREATEPALETTE *)mr;
1184

1185
	(handletable->objectHandle)[ lpCreatePal->ihPal ] =
1186 1187 1188 1189 1190 1191 1192
		CreatePalette( &lpCreatePal->lgpl );

	break;
      }

    case EMR_SELECTPALETTE:
      {
1193
	const EMRSELECTPALETTE *lpSelectPal = (const EMRSELECTPALETTE *)mr;
1194

1195 1196 1197 1198 1199
	if( lpSelectPal->ihPal & 0x80000000 ) {
		SelectPalette( hdc, GetStockObject(lpSelectPal->ihPal & 0x7fffffff), TRUE);
	} else {
		SelectPalette( hdc, (handletable->objectHandle)[lpSelectPal->ihPal], TRUE);
	}
1200 1201
	break;
      }
Alexandre Julliard's avatar
Alexandre Julliard committed
1202

1203 1204 1205 1206 1207 1208 1209 1210
    case EMR_REALIZEPALETTE:
      {
	RealizePalette( hdc );
	break;
      }

    case EMR_EXTSELECTCLIPRGN:
      {
1211 1212 1213 1214 1215
	const EMREXTSELECTCLIPRGN *lpRgn = (const EMREXTSELECTCLIPRGN *)mr;
	HRGN hRgn = 0;

        if (mr->nSize >= sizeof(*lpRgn) + sizeof(RGNDATAHEADER))
            hRgn = ExtCreateRegion( &info->init_transform, 0, (RGNDATA *)lpRgn->RgnData );
1216

1217 1218 1219
	ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode));
	/* ExtSelectClipRgn created a copy of the region */
	DeleteObject(hRgn);
1220
        break;
1221
      }
1222

1223 1224 1225 1226 1227
    case EMR_SETMETARGN:
      {
        SetMetaRgn( hdc );
        break;
      }
1228

1229 1230
    case EMR_SETWORLDTRANSFORM:
      {
1231
        const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)mr;
1232
        info->state.world_transform = lpXfrm->xform;
1233 1234
        break;
      }
1235

1236
    case EMR_POLYBEZIER:
1237
      {
1238
        const EMRPOLYBEZIER *lpPolyBez = (const EMRPOLYBEZIER *)mr;
1239
        PolyBezier(hdc, (const POINT*)lpPolyBez->aptl, (UINT)lpPolyBez->cptl);
1240 1241 1242
        break;
      }

1243
    case EMR_POLYGON:
1244
      {
1245
        const EMRPOLYGON *lpPoly = (const EMRPOLYGON *)mr;
1246
        Polygon( hdc, (const POINT*)lpPoly->aptl, (UINT)lpPoly->cptl );
1247 1248 1249
        break;
      }

1250
    case EMR_POLYLINE:
1251
      {
1252
        const EMRPOLYLINE *lpPolyLine = (const EMRPOLYLINE *)mr;
1253
        Polyline(hdc, (const POINT*)lpPolyLine->aptl, (UINT)lpPolyLine->cptl);
1254
        break;
1255 1256
      }

1257
    case EMR_POLYBEZIERTO:
1258
      {
1259
        const EMRPOLYBEZIERTO *lpPolyBezierTo = (const EMRPOLYBEZIERTO *)mr;
1260
        PolyBezierTo( hdc, (const POINT*)lpPolyBezierTo->aptl,
1261
		      (UINT)lpPolyBezierTo->cptl );
1262
        break;
1263 1264
      }

1265
    case EMR_POLYLINETO:
1266
      {
1267
        const EMRPOLYLINETO *lpPolyLineTo = (const EMRPOLYLINETO *)mr;
1268
        PolylineTo( hdc, (const POINT*)lpPolyLineTo->aptl,
1269
		    (UINT)lpPolyLineTo->cptl );
1270 1271 1272
        break;
      }

1273
    case EMR_POLYPOLYLINE:
1274
      {
1275
        const EMRPOLYPOLYLINE *pPolyPolyline = (const EMRPOLYPOLYLINE *)mr;
1276
	/* NB Points at pPolyPolyline->aPolyCounts + pPolyPolyline->nPolys */
1277

1278
        PolyPolyline(hdc, (LPPOINT)(pPolyPolyline->aPolyCounts +
1279 1280 1281
				    pPolyPolyline->nPolys),
		     pPolyPolyline->aPolyCounts,
		     pPolyPolyline->nPolys );
1282 1283 1284 1285

        break;
      }

1286
    case EMR_POLYPOLYGON:
1287
      {
1288
        const EMRPOLYPOLYGON *pPolyPolygon = (const EMRPOLYPOLYGON *)mr;
1289

1290
	/* NB Points at pPolyPolygon->aPolyCounts + pPolyPolygon->nPolys */
1291

1292 1293 1294
        PolyPolygon(hdc, (LPPOINT)(pPolyPolygon->aPolyCounts +
				   pPolyPolygon->nPolys),
		    (INT*)pPolyPolygon->aPolyCounts, pPolyPolygon->nPolys );
1295 1296 1297
        break;
      }

1298
    case EMR_SETBRUSHORGEX:
1299
      {
1300
        const EMRSETBRUSHORGEX *lpSetBrushOrgEx = (const EMRSETBRUSHORGEX *)mr;
1301

1302 1303 1304
        SetBrushOrgEx( hdc,
                       (INT)lpSetBrushOrgEx->ptlOrigin.x,
                       (INT)lpSetBrushOrgEx->ptlOrigin.y,
1305 1306 1307 1308
                       NULL );

        break;
      }
1309

1310
    case EMR_SETPIXELV:
1311
      {
1312
        const EMRSETPIXELV *lpSetPixelV = (const EMRSETPIXELV *)mr;
1313

1314 1315 1316
        SetPixelV( hdc,
                   (INT)lpSetPixelV->ptlPixel.x,
                   (INT)lpSetPixelV->ptlPixel.y,
1317 1318 1319 1320 1321
                   lpSetPixelV->crColor );

        break;
      }

1322
    case EMR_SETMAPPERFLAGS:
1323
      {
1324
        const EMRSETMAPPERFLAGS *lpSetMapperFlags = (const EMRSETMAPPERFLAGS *)mr;
1325

1326 1327 1328 1329 1330
        SetMapperFlags( hdc, lpSetMapperFlags->dwFlags );

        break;
      }

1331
    case EMR_SETCOLORADJUSTMENT:
1332
      {
1333
        const EMRSETCOLORADJUSTMENT *lpSetColorAdjust = (const EMRSETCOLORADJUSTMENT *)mr;
1334 1335 1336 1337 1338 1339

        SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment );

        break;
      }

1340
    case EMR_OFFSETCLIPRGN:
1341
      {
1342
        const EMROFFSETCLIPRGN *lpOffsetClipRgn = (const EMROFFSETCLIPRGN *)mr;
1343

1344
        OffsetClipRgn( hdc,
1345 1346
                       (INT)lpOffsetClipRgn->ptlOffset.x,
                       (INT)lpOffsetClipRgn->ptlOffset.y );
1347
        FIXME("OffsetClipRgn\n");
1348 1349

        break;
1350
      }
1351

1352
    case EMR_EXCLUDECLIPRECT:
1353
      {
1354
        const EMREXCLUDECLIPRECT *lpExcludeClipRect = (const EMREXCLUDECLIPRECT *)mr;
1355

1356 1357 1358 1359
        ExcludeClipRect( hdc,
                         lpExcludeClipRect->rclClip.left,
                         lpExcludeClipRect->rclClip.top,
                         lpExcludeClipRect->rclClip.right,
1360
                         lpExcludeClipRect->rclClip.bottom  );
1361
        FIXME("ExcludeClipRect\n");
1362 1363 1364 1365

         break;
      }

1366
    case EMR_SCALEVIEWPORTEXTEX:
1367
      {
1368
        const EMRSCALEVIEWPORTEXTEX *lpScaleViewportExtEx = (const EMRSCALEVIEWPORTEXTEX *)mr;
1369

1370
        if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
1371 1372
	    break;
        if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom || 
1373
            !lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom)
1374
            break;
1375
        info->state.vportExtX = MulDiv(info->state.vportExtX, lpScaleViewportExtEx->xNum,
1376
                                 lpScaleViewportExtEx->xDenom);
1377
        info->state.vportExtY = MulDiv(info->state.vportExtY, lpScaleViewportExtEx->yNum,
1378
                                 lpScaleViewportExtEx->yDenom);
1379 1380 1381
        if (info->state.vportExtX == 0) info->state.vportExtX = 1;
        if (info->state.vportExtY == 0) info->state.vportExtY = 1;
        if (info->state.mode == MM_ISOTROPIC)
1382
            EMF_FixIsotropic(hdc, info);
1383

1384
        TRACE("EMRSCALEVIEWPORTEXTEX %d/%d %d/%d\n",
1385 1386
             lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom,
             lpScaleViewportExtEx->yNum,lpScaleViewportExtEx->yDenom);
1387

1388 1389
        break;
      }
1390

1391
    case EMR_SCALEWINDOWEXTEX:
1392
      {
1393
        const EMRSCALEWINDOWEXTEX *lpScaleWindowExtEx = (const EMRSCALEWINDOWEXTEX *)mr;
1394

1395
        if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
1396 1397 1398 1399
	    break;
        if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom || 
            !lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->yDenom)
            break;
1400
        info->state.wndExtX = MulDiv(info->state.wndExtX, lpScaleWindowExtEx->xNum,
1401
                               lpScaleWindowExtEx->xDenom);
1402
        info->state.wndExtY = MulDiv(info->state.wndExtY, lpScaleWindowExtEx->yNum,
1403
                               lpScaleWindowExtEx->yDenom);
1404 1405 1406
        if (info->state.wndExtX == 0) info->state.wndExtX = 1;
        if (info->state.wndExtY == 0) info->state.wndExtY = 1;
        if (info->state.mode == MM_ISOTROPIC)
1407
            EMF_FixIsotropic(hdc, info);
1408

1409
        TRACE("EMRSCALEWINDOWEXTEX %d/%d %d/%d\n",
1410 1411
             lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom,
             lpScaleWindowExtEx->yNum,lpScaleWindowExtEx->yDenom);
1412 1413 1414 1415

        break;
      }

1416
    case EMR_MODIFYWORLDTRANSFORM:
1417
      {
1418
        const EMRMODIFYWORLDTRANSFORM *lpModifyWorldTrans = (const EMRMODIFYWORLDTRANSFORM *)mr;
1419

1420 1421
        switch(lpModifyWorldTrans->iMode) {
        case MWT_IDENTITY:
1422 1423 1424
            info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
            info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
            info->state.world_transform.eDx  = info->state.world_transform.eDy  = 0;
1425 1426
            break;
        case MWT_LEFTMULTIPLY:
1427 1428
            CombineTransform(&info->state.world_transform, &lpModifyWorldTrans->xform,
                             &info->state.world_transform);
1429 1430
            break;
        case MWT_RIGHTMULTIPLY:
1431
            CombineTransform(&info->state.world_transform, &info->state.world_transform,
1432 1433 1434
                             &lpModifyWorldTrans->xform);
            break;
        default:
1435
            FIXME("Unknown imode %d\n", lpModifyWorldTrans->iMode);
1436 1437
            break;
        }
1438 1439 1440
        break;
      }

1441
    case EMR_ANGLEARC:
1442
      {
1443
        const EMRANGLEARC *lpAngleArc = (const EMRANGLEARC *)mr;
1444

1445
        AngleArc( hdc,
1446
                 (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y,
1447
                 lpAngleArc->nRadius, lpAngleArc->eStartAngle,
1448 1449 1450 1451
                 lpAngleArc->eSweepAngle );

        break;
      }
1452 1453

    case EMR_ROUNDRECT:
1454
      {
1455
        const EMRROUNDRECT *lpRoundRect = (const EMRROUNDRECT *)mr;
1456

1457
        RoundRect( hdc,
1458 1459 1460 1461 1462 1463 1464
                   lpRoundRect->rclBox.left,
                   lpRoundRect->rclBox.top,
                   lpRoundRect->rclBox.right,
                   lpRoundRect->rclBox.bottom,
                   lpRoundRect->szlCorner.cx,
                   lpRoundRect->szlCorner.cy );

1465
        break;
1466 1467
      }

1468
    case EMR_ARC:
1469
      {
1470
        const EMRARC *lpArc = (const EMRARC *)mr;
1471

1472
        Arc( hdc,
1473 1474 1475 1476
             (INT)lpArc->rclBox.left,
             (INT)lpArc->rclBox.top,
             (INT)lpArc->rclBox.right,
             (INT)lpArc->rclBox.bottom,
1477
             (INT)lpArc->ptlStart.x,
1478 1479 1480 1481
             (INT)lpArc->ptlStart.y,
             (INT)lpArc->ptlEnd.x,
             (INT)lpArc->ptlEnd.y );

1482
        break;
1483 1484
      }

1485
    case EMR_CHORD:
1486
      {
1487
        const EMRCHORD *lpChord = (const EMRCHORD *)mr;
1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501

        Chord( hdc,
             (INT)lpChord->rclBox.left,
             (INT)lpChord->rclBox.top,
             (INT)lpChord->rclBox.right,
             (INT)lpChord->rclBox.bottom,
             (INT)lpChord->ptlStart.x,
             (INT)lpChord->ptlStart.y,
             (INT)lpChord->ptlEnd.x,
             (INT)lpChord->ptlEnd.y );

        break;
      }

1502
    case EMR_PIE:
1503
      {
1504
        const EMRPIE *lpPie = (const EMRPIE *)mr;
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518

        Pie( hdc,
             (INT)lpPie->rclBox.left,
             (INT)lpPie->rclBox.top,
             (INT)lpPie->rclBox.right,
             (INT)lpPie->rclBox.bottom,
             (INT)lpPie->ptlStart.x,
             (INT)lpPie->ptlStart.y,
             (INT)lpPie->ptlEnd.x,
             (INT)lpPie->ptlEnd.y );

       break;
      }

1519
    case EMR_ARCTO:
1520
      {
1521
        const EMRARC *lpArcTo = (const EMRARC *)mr;
1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537

        ArcTo( hdc,
               (INT)lpArcTo->rclBox.left,
               (INT)lpArcTo->rclBox.top,
               (INT)lpArcTo->rclBox.right,
               (INT)lpArcTo->rclBox.bottom,
               (INT)lpArcTo->ptlStart.x,
               (INT)lpArcTo->ptlStart.y,
               (INT)lpArcTo->ptlEnd.x,
               (INT)lpArcTo->ptlEnd.y );

        break;
      }

    case EMR_EXTFLOODFILL:
      {
1538
        const EMREXTFLOODFILL *lpExtFloodFill = (const EMREXTFLOODFILL *)mr;
1539

1540
        ExtFloodFill( hdc,
1541 1542 1543 1544 1545 1546 1547 1548
                      (INT)lpExtFloodFill->ptlStart.x,
                      (INT)lpExtFloodFill->ptlStart.y,
                      lpExtFloodFill->crColor,
                      (UINT)lpExtFloodFill->iMode );

        break;
      }

1549
    case EMR_POLYDRAW:
1550
      {
1551
        const EMRPOLYDRAW *lpPolyDraw = (const EMRPOLYDRAW *)mr;
1552
        PolyDraw( hdc,
1553
                  (const POINT*)lpPolyDraw->aptl,
1554 1555
                  lpPolyDraw->abTypes,
                  (INT)lpPolyDraw->cptl );
1556

1557
        break;
1558
      }
1559

1560
    case EMR_SETARCDIRECTION:
1561
      {
1562
        const EMRSETARCDIRECTION *lpSetArcDirection = (const EMRSETARCDIRECTION *)mr;
1563 1564 1565 1566
        SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection );
        break;
      }

1567
    case EMR_SETMITERLIMIT:
1568
      {
1569
        const EMRSETMITERLIMIT *lpSetMiterLimit = (const EMRSETMITERLIMIT *)mr;
1570 1571
        SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL );
        break;
1572
      }
1573

1574
    case EMR_BEGINPATH:
1575 1576 1577 1578 1579
      {
        BeginPath( hdc );
        break;
      }

1580
    case EMR_ENDPATH:
1581 1582 1583 1584 1585
      {
        EndPath( hdc );
        break;
      }

1586
    case EMR_CLOSEFIGURE:
1587 1588 1589 1590 1591
      {
        CloseFigure( hdc );
        break;
      }

1592
    case EMR_FILLPATH:
1593
      {
1594
        /*const EMRFILLPATH lpFillPath = (const EMRFILLPATH *)mr;*/
1595 1596 1597 1598
        FillPath( hdc );
        break;
      }

1599
    case EMR_STROKEANDFILLPATH:
1600
      {
1601
        /*const EMRSTROKEANDFILLPATH lpStrokeAndFillPath = (const EMRSTROKEANDFILLPATH *)mr;*/
1602 1603 1604 1605
        StrokeAndFillPath( hdc );
        break;
      }

1606
    case EMR_STROKEPATH:
1607
      {
1608
        /*const EMRSTROKEPATH lpStrokePath = (const EMRSTROKEPATH *)mr;*/
1609 1610 1611 1612
        StrokePath( hdc );
        break;
      }

1613
    case EMR_FLATTENPATH:
1614
      {
1615
        FlattenPath( hdc );
1616 1617 1618
        break;
      }

1619
    case EMR_WIDENPATH:
1620 1621 1622 1623 1624
      {
        WidenPath( hdc );
        break;
      }

1625
    case EMR_SELECTCLIPPATH:
1626
      {
1627
        const EMRSELECTCLIPPATH *lpSelectClipPath = (const EMRSELECTCLIPPATH *)mr;
1628 1629 1630
        SelectClipPath( hdc, (INT)lpSelectClipPath->iMode );
        break;
      }
1631

1632
    case EMR_ABORTPATH:
1633 1634 1635 1636 1637
      {
        AbortPath( hdc );
        break;
      }

1638 1639 1640
    case EMR_CREATECOLORSPACE:
      {
        PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr;
1641 1642
        (handletable->objectHandle)[lpCreateColorSpace->ihCS] =
           CreateColorSpaceA( &lpCreateColorSpace->lcs );
1643 1644 1645 1646 1647
        break;
      }

    case EMR_SETCOLORSPACE:
      {
1648
        const EMRSETCOLORSPACE *lpSetColorSpace = (const EMRSETCOLORSPACE *)mr;
1649
        SetColorSpace( hdc,
1650 1651 1652 1653 1654 1655
                       (handletable->objectHandle)[lpSetColorSpace->ihCS] );
        break;
      }

    case EMR_DELETECOLORSPACE:
      {
1656
        const EMRDELETECOLORSPACE *lpDeleteColorSpace = (const EMRDELETECOLORSPACE *)mr;
1657
        DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] );
1658
        break;
1659 1660 1661 1662
      }

    case EMR_SETICMMODE:
      {
1663
        const EMRSETICMMODE *lpSetICMMode = (const EMRSETICMMODE *)mr;
1664
        SetICMMode( hdc, (INT)lpSetICMMode->iMode );
1665 1666 1667
        break;
      }

1668
    case EMR_PIXELFORMAT:
1669 1670
      {
        INT iPixelFormat;
1671
        const EMRPIXELFORMAT *lpPixelFormat = (const EMRPIXELFORMAT *)mr;
1672 1673

        iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd );
1674 1675
        SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd );

1676 1677 1678
        break;
      }

1679
    case EMR_SETPALETTEENTRIES:
1680
      {
1681
        const EMRSETPALETTEENTRIES *lpSetPaletteEntries = (const EMRSETPALETTEENTRIES *)mr;
1682 1683 1684 1685

        SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal],
                           (UINT)lpSetPaletteEntries->iStart,
                           (UINT)lpSetPaletteEntries->cEntries,
1686 1687
                           lpSetPaletteEntries->aPalEntries );

1688 1689 1690 1691 1692
        break;
      }

    case EMR_RESIZEPALETTE:
      {
1693
        const EMRRESIZEPALETTE *lpResizePalette = (const EMRRESIZEPALETTE *)mr;
1694 1695 1696 1697 1698 1699 1700 1701 1702

        ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal],
                       (UINT)lpResizePalette->cEntries );

        break;
      }

    case EMR_CREATEDIBPATTERNBRUSHPT:
      {
1703
        const EMRCREATEDIBPATTERNBRUSHPT *lpCreate = (const EMRCREATEDIBPATTERNBRUSHPT *)mr;
1704 1705
        LPVOID lpPackedStruct;

1706
        /* Check that offsets and data are contained within the record
Austin English's avatar
Austin English committed
1707
         * (including checking for wrap-arounds).
1708 1709 1710 1711 1712
         */
        if (    lpCreate->offBmi  + lpCreate->cbBmi  > mr->nSize
             || lpCreate->offBits + lpCreate->cbBits > mr->nSize
             || lpCreate->offBmi  + lpCreate->cbBmi  < lpCreate->offBmi
             || lpCreate->offBits + lpCreate->cbBits < lpCreate->offBits )
1713 1714 1715 1716
        {
            ERR("Invalid EMR_CREATEDIBPATTERNBRUSHPT record\n");
            break;
        }
1717 1718

        /* This is a BITMAPINFO struct followed directly by bitmap bits */
1719 1720 1721 1722
        lpPackedStruct = HeapAlloc( GetProcessHeap(), 0,
                                    lpCreate->cbBmi + lpCreate->cbBits );
        if(!lpPackedStruct)
        {
1723
            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1724 1725 1726
            break;
        }

1727
        /* Now pack this structure */
1728
        memcpy( lpPackedStruct,
1729
                ((const BYTE *)lpCreate) + lpCreate->offBmi,
1730
                lpCreate->cbBmi );
1731
        memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi,
1732
                ((const BYTE *)lpCreate) + lpCreate->offBits,
1733 1734
                lpCreate->cbBits );

1735
        (handletable->objectHandle)[lpCreate->ihBrush] =
1736
           CreateDIBPatternBrushPt( lpPackedStruct,
1737
                                    (UINT)lpCreate->iUsage );
1738

1739
        HeapFree(GetProcessHeap(), 0, lpPackedStruct);
1740
        break;
1741
      }
1742

1743 1744
    case EMR_CREATEMONOBRUSH:
    {
1745
        const EMRCREATEMONOBRUSH *pCreateMonoBrush = (const EMRCREATEMONOBRUSH *)mr;
1746
        const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pCreateMonoBrush->offBmi);
1747 1748 1749 1750
        HBITMAP hBmp;

        /* Need to check if the bitmap is monochrome, and if the
           two colors are really black and white */
1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767
        if (pCreateMonoBrush->iUsage == DIB_PAL_MONO)
        {
            BITMAP bm;

            /* Undocumented iUsage indicates a mono bitmap with no palette table,
             * aligned to 32 rather than 16 bits.
             */
            bm.bmType = 0;
            bm.bmWidth = pbi->bmiHeader.biWidth;
            bm.bmHeight = abs(pbi->bmiHeader.biHeight);
            bm.bmWidthBytes = 4 * ((pbi->bmiHeader.biWidth + 31) / 32);
            bm.bmPlanes = pbi->bmiHeader.biPlanes;
            bm.bmBitsPixel = pbi->bmiHeader.biBitCount;
            bm.bmBits = (BYTE *)mr + pCreateMonoBrush->offBits;
            hBmp = CreateBitmapIndirect(&bm);
        }
        else if (is_dib_monochrome(pbi))
1768 1769 1770 1771
        {
          /* Top-down DIBs have a negative height */
          LONG height = pbi->bmiHeader.biHeight;

1772
          hBmp = CreateBitmap(pbi->bmiHeader.biWidth, abs(height), 1, 1, NULL);
1773
          SetDIBits(hdc, hBmp, 0, pbi->bmiHeader.biHeight,
1774
              (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1775
        }
1776 1777
        else
        {
1778 1779
            hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
              (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1780 1781
        }

1782
	(handletable->objectHandle)[pCreateMonoBrush->ihBrush] = CreatePatternBrush(hBmp);
1783

1784 1785 1786 1787 1788
	/* CreatePatternBrush created a copy of the bitmap */
	DeleteObject(hBmp);
	break;
    }

1789
    case EMR_BITBLT:
1790
    {
1791
	const EMRBITBLT *pBitBlt = (const EMRBITBLT *)mr;
1792

1793 1794 1795 1796 1797 1798 1799
        if(pBitBlt->offBmiSrc == 0) { /* Record is a PatBlt */
            PatBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest,
                   pBitBlt->dwRop);
        } else { /* BitBlt */
            HDC hdcSrc = CreateCompatibleDC(hdc);
            HBRUSH hBrush, hBrushOld;
            HBITMAP hBmp = 0, hBmpOld = 0;
1800
            const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pBitBlt->offBmiSrc);
1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811

            SetWorldTransform(hdcSrc, &pBitBlt->xformSrc);

            hBrush = CreateSolidBrush(pBitBlt->crBkColorSrc);
            hBrushOld = SelectObject(hdcSrc, hBrush);
            PatBlt(hdcSrc, pBitBlt->rclBounds.left, pBitBlt->rclBounds.top,
                   pBitBlt->rclBounds.right - pBitBlt->rclBounds.left,
                   pBitBlt->rclBounds.bottom - pBitBlt->rclBounds.top, PATCOPY);
            SelectObject(hdcSrc, hBrushOld);
            DeleteObject(hBrush);

1812 1813
            hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
                                  (const BYTE *)mr + pBitBlt->offBitsSrc, pbi, pBitBlt->iUsageSrc);
1814 1815 1816 1817 1818 1819 1820 1821 1822
            hBmpOld = SelectObject(hdcSrc, hBmp);

            BitBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest,
                   hdcSrc, pBitBlt->xSrc, pBitBlt->ySrc, pBitBlt->dwRop);

            SelectObject(hdcSrc, hBmpOld);
            DeleteObject(hBmp);
            DeleteDC(hdcSrc);
        }
1823 1824 1825
	break;
    }

1826
    case EMR_STRETCHBLT:
1827
    {
1828
	const EMRSTRETCHBLT *pStretchBlt = (const EMRSTRETCHBLT *)mr;
1829

1830
        TRACE("EMR_STRETCHBLT: %d, %d %dx%d -> %d, %d %dx%d. rop %08x offBitsSrc %d\n",
1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841
	       pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc,
	       pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
	       pStretchBlt->dwRop, pStretchBlt->offBitsSrc);

        if(pStretchBlt->offBmiSrc == 0) { /* Record is a PatBlt */
            PatBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
                   pStretchBlt->dwRop);
        } else { /* StretchBlt */
            HDC hdcSrc = CreateCompatibleDC(hdc);
            HBRUSH hBrush, hBrushOld;
            HBITMAP hBmp = 0, hBmpOld = 0;
1842
            const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pStretchBlt->offBmiSrc);
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853

            SetWorldTransform(hdcSrc, &pStretchBlt->xformSrc);

            hBrush = CreateSolidBrush(pStretchBlt->crBkColorSrc);
            hBrushOld = SelectObject(hdcSrc, hBrush);
            PatBlt(hdcSrc, pStretchBlt->rclBounds.left, pStretchBlt->rclBounds.top,
                   pStretchBlt->rclBounds.right - pStretchBlt->rclBounds.left,
                   pStretchBlt->rclBounds.bottom - pStretchBlt->rclBounds.top, PATCOPY);
            SelectObject(hdcSrc, hBrushOld);
            DeleteObject(hBrush);

1854 1855
            hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
                                  (const BYTE *)mr + pStretchBlt->offBitsSrc, pbi, pStretchBlt->iUsageSrc);
1856 1857 1858 1859 1860 1861 1862 1863 1864 1865
            hBmpOld = SelectObject(hdcSrc, hBmp);

            StretchBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
                       hdcSrc, pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc,
                       pStretchBlt->dwRop);

            SelectObject(hdcSrc, hBmpOld);
            DeleteObject(hBmp);
            DeleteDC(hdcSrc);
        }
1866 1867 1868
	break;
    }

1869 1870
    case EMR_ALPHABLEND:
    {
1871
	const EMRALPHABLEND *pAlphaBlend = (const EMRALPHABLEND *)mr;
1872

1873
        TRACE("EMR_ALPHABLEND: %d, %d %dx%d -> %d, %d %dx%d. blendfn %08x offBitsSrc %d\n",
1874 1875 1876 1877 1878 1879 1880 1881 1882
	       pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc,
	       pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest,
	       pAlphaBlend->dwRop, pAlphaBlend->offBitsSrc);

        if(pAlphaBlend->offBmiSrc == 0) {
            FIXME("EMR_ALPHABLEND: offBmiSrc == 0\n");
        } else {
            HDC hdcSrc = CreateCompatibleDC(hdc);
            HBITMAP hBmp = 0, hBmpOld = 0;
1883
            const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pAlphaBlend->offBmiSrc);
1884 1885 1886 1887 1888 1889
            BLENDFUNCTION blendfn;
            void *bits;

            SetWorldTransform(hdcSrc, &pAlphaBlend->xformSrc);

            hBmp = CreateDIBSection(hdc, pbi, pAlphaBlend->iUsageSrc, &bits, NULL, 0);
1890
            memcpy(bits, (const BYTE *)mr + pAlphaBlend->offBitsSrc, pAlphaBlend->cbBitsSrc);
1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908
            hBmpOld = SelectObject(hdcSrc, hBmp);

            blendfn.BlendOp             = (pAlphaBlend->dwRop >> 24) & 0xff;
            blendfn.BlendFlags          = (pAlphaBlend->dwRop >> 16) & 0xff;
            blendfn.SourceConstantAlpha = (pAlphaBlend->dwRop >>  8) & 0xff;
            blendfn.AlphaFormat         = (pAlphaBlend->dwRop) & 0xff;

            GdiAlphaBlend(hdc, pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest,
                       hdcSrc, pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc,
                       blendfn);

            SelectObject(hdcSrc, hBmpOld);
            DeleteObject(hBmp);
            DeleteDC(hdcSrc);
        }
	break;
    }

1909
    case EMR_MASKBLT:
1910
    {
1911
	const EMRMASKBLT *pMaskBlt = (const EMRMASKBLT *)mr;
1912 1913 1914
	HDC hdcSrc = CreateCompatibleDC(hdc);
	HBRUSH hBrush, hBrushOld;
	HBITMAP hBmp, hBmpOld, hBmpMask;
1915
	const BITMAPINFO *pbi;
1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926

	SetWorldTransform(hdcSrc, &pMaskBlt->xformSrc);

	hBrush = CreateSolidBrush(pMaskBlt->crBkColorSrc);
	hBrushOld = SelectObject(hdcSrc, hBrush);
	PatBlt(hdcSrc, pMaskBlt->rclBounds.left, pMaskBlt->rclBounds.top,
	       pMaskBlt->rclBounds.right - pMaskBlt->rclBounds.left,
	       pMaskBlt->rclBounds.bottom - pMaskBlt->rclBounds.top, PATCOPY);
	SelectObject(hdcSrc, hBrushOld);
	DeleteObject(hBrush);

1927
	pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiMask);
1928 1929 1930
	hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight,
	             1, 1, NULL);
	SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight,
1931
	  (const BYTE *)mr + pMaskBlt->offBitsMask, pbi, pMaskBlt->iUsageMask);
1932

1933 1934 1935
	pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiSrc);
	hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
			      (const BYTE *)mr + pMaskBlt->offBitsSrc, pbi, pMaskBlt->iUsageSrc);
1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955
	hBmpOld = SelectObject(hdcSrc, hBmp);
	MaskBlt(hdc,
		pMaskBlt->xDest,
	        pMaskBlt->yDest,
	        pMaskBlt->cxDest,
	        pMaskBlt->cyDest,
	        hdcSrc,
	        pMaskBlt->xSrc,
	        pMaskBlt->ySrc,
	        hBmpMask,
		pMaskBlt->xMask,
		pMaskBlt->yMask,
	        pMaskBlt->dwRop);
	SelectObject(hdcSrc, hBmpOld);
	DeleteObject(hBmp);
	DeleteObject(hBmpMask);
	DeleteDC(hdcSrc);
	break;
    }

1956
    case EMR_PLGBLT:
1957
    {
1958
	const EMRPLGBLT *pPlgBlt = (const EMRPLGBLT *)mr;
1959 1960 1961
	HDC hdcSrc = CreateCompatibleDC(hdc);
	HBRUSH hBrush, hBrushOld;
	HBITMAP hBmp, hBmpOld, hBmpMask;
1962
	const BITMAPINFO *pbi;
1963 1964 1965 1966
	POINT pts[3];

	SetWorldTransform(hdcSrc, &pPlgBlt->xformSrc);

1967 1968 1969
	pts[0].x = pPlgBlt->aptlDest[0].x; pts[0].y = pPlgBlt->aptlDest[0].y;
	pts[1].x = pPlgBlt->aptlDest[1].x; pts[1].y = pPlgBlt->aptlDest[1].y;
	pts[2].x = pPlgBlt->aptlDest[2].x; pts[2].y = pPlgBlt->aptlDest[2].y;
1970 1971 1972 1973 1974 1975 1976 1977 1978

	hBrush = CreateSolidBrush(pPlgBlt->crBkColorSrc);
	hBrushOld = SelectObject(hdcSrc, hBrush);
	PatBlt(hdcSrc, pPlgBlt->rclBounds.left, pPlgBlt->rclBounds.top,
	       pPlgBlt->rclBounds.right - pPlgBlt->rclBounds.left,
	       pPlgBlt->rclBounds.bottom - pPlgBlt->rclBounds.top, PATCOPY);
	SelectObject(hdcSrc, hBrushOld);
	DeleteObject(hBrush);

1979
	pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiMask);
1980 1981 1982
	hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight,
	             1, 1, NULL);
	SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight,
1983
	  (const BYTE *)mr + pPlgBlt->offBitsMask, pbi, pPlgBlt->iUsageMask);
1984

1985 1986 1987
	pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiSrc);
	hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
			      (const BYTE *)mr + pPlgBlt->offBitsSrc, pbi, pPlgBlt->iUsageSrc);
1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005
	hBmpOld = SelectObject(hdcSrc, hBmp);
	PlgBlt(hdc,
	       pts,
	       hdcSrc,
	       pPlgBlt->xSrc,
	       pPlgBlt->ySrc,
	       pPlgBlt->cxSrc,
	       pPlgBlt->cySrc,
	       hBmpMask,
	       pPlgBlt->xMask,
	       pPlgBlt->yMask);
	SelectObject(hdcSrc, hBmpOld);
	DeleteObject(hBmp);
	DeleteObject(hBmpMask);
	DeleteDC(hdcSrc);
	break;
    }

2006
    case EMR_SETDIBITSTODEVICE:
2007
    {
2008
	const EMRSETDIBITSTODEVICE *pSetDIBitsToDevice = (const EMRSETDIBITSTODEVICE *)mr;
2009 2010 2011 2012 2013 2014 2015 2016 2017 2018

	SetDIBitsToDevice(hdc,
			  pSetDIBitsToDevice->xDest,
			  pSetDIBitsToDevice->yDest,
			  pSetDIBitsToDevice->cxSrc,
			  pSetDIBitsToDevice->cySrc,
			  pSetDIBitsToDevice->xSrc,
			  pSetDIBitsToDevice->ySrc,
			  pSetDIBitsToDevice->iStartScan,
			  pSetDIBitsToDevice->cScans,
2019 2020
			  (const BYTE *)mr + pSetDIBitsToDevice->offBitsSrc,
			  (const BITMAPINFO *)((const BYTE *)mr + pSetDIBitsToDevice->offBmiSrc),
2021 2022 2023 2024
			  pSetDIBitsToDevice->iUsageSrc);
	break;
    }

2025
    case EMR_POLYTEXTOUTA:
2026
    {
2027
	const EMRPOLYTEXTOUTA *pPolyTextOutA = (const EMRPOLYTEXTOUTA *)mr;
2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049
	POLYTEXTA *polytextA = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutA->cStrings * sizeof(POLYTEXTA));
	LONG i;
	XFORM xform, xformOld;
	int gModeOld;

	gModeOld = SetGraphicsMode(hdc, pPolyTextOutA->iGraphicsMode);
	GetWorldTransform(hdc, &xformOld);

	xform.eM11 = pPolyTextOutA->exScale;
	xform.eM12 = 0.0;
	xform.eM21 = 0.0;
	xform.eM22 = pPolyTextOutA->eyScale;
	xform.eDx = 0.0;
	xform.eDy = 0.0;
	SetWorldTransform(hdc, &xform);

	/* Set up POLYTEXTA structures */
	for(i = 0; i < pPolyTextOutA->cStrings; i++)
	{
	    polytextA[i].x = pPolyTextOutA->aemrtext[i].ptlReference.x;
	    polytextA[i].y = pPolyTextOutA->aemrtext[i].ptlReference.y;
	    polytextA[i].n = pPolyTextOutA->aemrtext[i].nChars;
2050
	    polytextA[i].lpstr = (LPCSTR)((const BYTE *)mr + pPolyTextOutA->aemrtext[i].offString);
2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065
	    polytextA[i].uiFlags = pPolyTextOutA->aemrtext[i].fOptions;
	    polytextA[i].rcl.left = pPolyTextOutA->aemrtext[i].rcl.left;
	    polytextA[i].rcl.right = pPolyTextOutA->aemrtext[i].rcl.right;
	    polytextA[i].rcl.top = pPolyTextOutA->aemrtext[i].rcl.top;
	    polytextA[i].rcl.bottom = pPolyTextOutA->aemrtext[i].rcl.bottom;
	    polytextA[i].pdx = (int *)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offDx);
	}
	PolyTextOutA(hdc, polytextA, pPolyTextOutA->cStrings);
	HeapFree(GetProcessHeap(), 0, polytextA);

	SetWorldTransform(hdc, &xformOld);
	SetGraphicsMode(hdc, gModeOld);
	break;
    }

2066
    case EMR_POLYTEXTOUTW:
2067
    {
2068
	const EMRPOLYTEXTOUTW *pPolyTextOutW = (const EMRPOLYTEXTOUTW *)mr;
2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090
	POLYTEXTW *polytextW = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutW->cStrings * sizeof(POLYTEXTW));
	LONG i;
	XFORM xform, xformOld;
	int gModeOld;

	gModeOld = SetGraphicsMode(hdc, pPolyTextOutW->iGraphicsMode);
	GetWorldTransform(hdc, &xformOld);

	xform.eM11 = pPolyTextOutW->exScale;
	xform.eM12 = 0.0;
	xform.eM21 = 0.0;
	xform.eM22 = pPolyTextOutW->eyScale;
	xform.eDx = 0.0;
	xform.eDy = 0.0;
	SetWorldTransform(hdc, &xform);

	/* Set up POLYTEXTW structures */
	for(i = 0; i < pPolyTextOutW->cStrings; i++)
	{
	    polytextW[i].x = pPolyTextOutW->aemrtext[i].ptlReference.x;
	    polytextW[i].y = pPolyTextOutW->aemrtext[i].ptlReference.y;
	    polytextW[i].n = pPolyTextOutW->aemrtext[i].nChars;
2091
	    polytextW[i].lpstr = (LPCWSTR)((const BYTE *)mr + pPolyTextOutW->aemrtext[i].offString);
2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
	    polytextW[i].uiFlags = pPolyTextOutW->aemrtext[i].fOptions;
	    polytextW[i].rcl.left = pPolyTextOutW->aemrtext[i].rcl.left;
	    polytextW[i].rcl.right = pPolyTextOutW->aemrtext[i].rcl.right;
	    polytextW[i].rcl.top = pPolyTextOutW->aemrtext[i].rcl.top;
	    polytextW[i].rcl.bottom = pPolyTextOutW->aemrtext[i].rcl.bottom;
	    polytextW[i].pdx = (int *)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offDx);
	}
	PolyTextOutW(hdc, polytextW, pPolyTextOutW->cStrings);
	HeapFree(GetProcessHeap(), 0, polytextW);

	SetWorldTransform(hdc, &xformOld);
	SetGraphicsMode(hdc, gModeOld);
	break;
    }

2107
    case EMR_FILLRGN:
2108
    {
2109
	const EMRFILLRGN *pFillRgn = (const EMRFILLRGN *)mr;
2110 2111 2112 2113 2114 2115 2116 2117
	HRGN hRgn = ExtCreateRegion(NULL, pFillRgn->cbRgnData, (RGNDATA *)pFillRgn->RgnData);
	FillRgn(hdc,
		hRgn,
		(handletable->objectHandle)[pFillRgn->ihBrush]);
	DeleteObject(hRgn);
	break;
    }

2118
    case EMR_FRAMERGN:
2119
    {
2120
	const EMRFRAMERGN *pFrameRgn = (const EMRFRAMERGN *)mr;
2121 2122 2123 2124 2125 2126 2127 2128 2129 2130
	HRGN hRgn = ExtCreateRegion(NULL, pFrameRgn->cbRgnData, (RGNDATA *)pFrameRgn->RgnData);
	FrameRgn(hdc,
		 hRgn,
		 (handletable->objectHandle)[pFrameRgn->ihBrush],
		 pFrameRgn->szlStroke.cx,
		 pFrameRgn->szlStroke.cy);
	DeleteObject(hRgn);
	break;
    }

2131
    case EMR_INVERTRGN:
2132
    {
2133
	const EMRINVERTRGN *pInvertRgn = (const EMRINVERTRGN *)mr;
2134 2135 2136 2137 2138 2139
	HRGN hRgn = ExtCreateRegion(NULL, pInvertRgn->cbRgnData, (RGNDATA *)pInvertRgn->RgnData);
	InvertRgn(hdc, hRgn);
	DeleteObject(hRgn);
	break;
    }

2140
    case EMR_PAINTRGN:
2141
    {
2142
	const EMRPAINTRGN *pPaintRgn = (const EMRPAINTRGN *)mr;
2143 2144 2145 2146 2147 2148
	HRGN hRgn = ExtCreateRegion(NULL, pPaintRgn->cbRgnData, (RGNDATA *)pPaintRgn->RgnData);
	PaintRgn(hdc, hRgn);
	DeleteObject(hRgn);
	break;
    }

2149 2150
    case EMR_SETTEXTJUSTIFICATION:
    {
2151
	const EMRSETTEXTJUSTIFICATION *pSetTextJust = (const EMRSETTEXTJUSTIFICATION *)mr;
2152 2153 2154 2155 2156 2157
	SetTextJustification(hdc, pSetTextJust->nBreakExtra, pSetTextJust->nBreakCount);
	break;
    }

    case EMR_SETLAYOUT:
    {
2158
	const EMRSETLAYOUT *pSetLayout = (const EMRSETLAYOUT *)mr;
2159 2160 2161 2162
	SetLayout(hdc, pSetLayout->iMode);
	break;
    }

2163
    case EMR_POLYDRAW16:
2164 2165
    case EMR_GLSRECORD:
    case EMR_GLSBOUNDEDRECORD:
2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180
	case EMR_DRAWESCAPE :
	case EMR_EXTESCAPE:
	case EMR_STARTDOC:
	case EMR_SMALLTEXTOUT:
	case EMR_FORCEUFIMAPPING:
	case EMR_NAMEDESCAPE:
	case EMR_COLORCORRECTPALETTE:
	case EMR_SETICMPROFILEA:
	case EMR_SETICMPROFILEW:
	case EMR_TRANSPARENTBLT:
	case EMR_GRADIENTFILL:
	case EMR_SETLINKEDUFI:
	case EMR_COLORMATCHTOTARGETW:
	case EMR_CREATECOLORSPACEW:

Alexandre Julliard's avatar
Alexandre Julliard committed
2181
    default:
2182
      /* From docs: If PlayEnhMetaFileRecord doesn't recognize a
2183
                    record then ignore and return TRUE. */
2184
      FIXME("type %d is unimplemented\n", type);
Alexandre Julliard's avatar
Alexandre Julliard committed
2185 2186
      break;
    }
2187 2188 2189
  tmprc.left = tmprc.top = 0;
  tmprc.right = tmprc.bottom = 1000;
  LPtoDP(hdc, (POINT*)&tmprc, 2);
2190
  TRACE("L:0,0 - 1000,1000 -> D:%d,%d - %d,%d\n", tmprc.left,
2191 2192
	tmprc.top, tmprc.right, tmprc.bottom);

Alexandre Julliard's avatar
Alexandre Julliard committed
2193
  return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
2194 2195 2196 2197 2198
}


/*****************************************************************************
 *
2199
 *        EnumEnhMetaFile  (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2200 2201 2202
 *
 *  Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
 *  for each
2203
 *  record. Returns when either every record has been used or
Alexandre Julliard's avatar
Alexandre Julliard committed
2204 2205 2206 2207 2208 2209 2210 2211
 *  when _EnhMetaFunc_ returns FALSE.
 *
 *
 * RETURNS
 *  TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
 *  returns FALSE.
 *
 * BUGS
Alexandre Julliard's avatar
Alexandre Julliard committed
2212
 *   Ignores rect.
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229
 *
 * NOTES
 *   This function behaves differently in Win9x and WinNT.
 *
 *   In WinNT, the DC's world transform is updated as the EMF changes
 *    the Window/Viewport Extent and Origin or it's world transform.
 *    The actual Window/Viewport Extent and Origin are left untouched.
 *
 *   In Win9x, the DC is left untouched, and PlayEnhMetaFileRecord
 *    updates the scaling itself but only just before a record that
 *    writes anything to the DC.
 *
 *   I'm not sure where the data (enum_emh_data) is stored in either
 *    version. For this implementation, it is stored before the handle
 *    table, but it could be stored in the DC, in the EMF handle or in
 *    TLS.
 *             MJM  5 Oct 2002
Alexandre Julliard's avatar
Alexandre Julliard committed
2230
 */
2231
BOOL WINAPI EnumEnhMetaFile(
2232 2233
     HDC hdc,                /* [in] device context to pass to _EnhMetaFunc_ */
     HENHMETAFILE hmf,       /* [in] EMF to walk */
2234
     ENHMFENUMPROC callback, /* [in] callback function */
2235 2236
     LPVOID data,            /* [in] optional data for callback function */
     const RECT *lpRect      /* [in] bounding rectangle for rendered metafile */
Alexandre Julliard's avatar
Alexandre Julliard committed
2237 2238
    )
{
2239
    BOOL ret;
2240
    ENHMETAHEADER *emh;
2241 2242
    ENHMETARECORD *emr;
    DWORD offset;
2243
    UINT i;
2244
    HANDLETABLE *ht;
2245
    INT savedMode = 0;
2246
    XFORM savedXform;
2247 2248 2249
    HPEN hPen = NULL;
    HBRUSH hBrush = NULL;
    HFONT hFont = NULL;
2250
    HRGN hRgn = NULL;
2251 2252 2253
    enum_emh_data *info;
    SIZE vp_size, win_size;
    POINT vp_org, win_org;
2254
    INT mapMode = MM_TEXT, old_align = 0, old_rop2 = 0, old_arcdir = 0, old_polyfill = 0, old_stretchblt = 0;
2255
    COLORREF old_text_color = 0, old_bk_color = 0;
2256

2257
    if(!lpRect && hdc)
2258 2259 2260 2261 2262 2263
    {
	SetLastError(ERROR_INVALID_PARAMETER);
	return FALSE;
    }

    emh = EMF_GetEnhMetaHeader(hmf);
2264 2265 2266 2267
    if(!emh) {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }
2268

2269
    info = HeapAlloc( GetProcessHeap(), 0,
2270 2271
		    sizeof (enum_emh_data) + sizeof(HANDLETABLE) * emh->nHandles );
    if(!info)
2272 2273 2274 2275
    {
	SetLastError(ERROR_NOT_ENOUGH_MEMORY);
	return FALSE;
    }
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287
    info->state.wndOrgX = 0;
    info->state.wndOrgY = 0;
    info->state.wndExtX = 1;
    info->state.wndExtY = 1;
    info->state.vportOrgX = 0;
    info->state.vportOrgY = 0;
    info->state.vportExtX = 1;
    info->state.vportExtY = 1;
    info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
    info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
    info->state.world_transform.eDx  = info->state.world_transform.eDy =  0;

2288
    info->state.next = NULL;
2289 2290
    info->save_level = 0;
    info->saved_state = NULL;
2291 2292

    ht = (HANDLETABLE*) &info[1];
2293
    ht->objectHandle[0] = hmf;
2294 2295
    for(i = 1; i < emh->nHandles; i++)
        ht->objectHandle[i] = NULL;
2296

2297
    if(hdc)
2298 2299 2300
    {
	savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
	GetWorldTransform(hdc, &savedXform);
2301 2302 2303 2304 2305
        GetViewportExtEx(hdc, &vp_size);
        GetWindowExtEx(hdc, &win_size);
        GetViewportOrgEx(hdc, &vp_org);
        GetWindowOrgEx(hdc, &win_org);
        mapMode = GetMapMode(hdc);
2306

2307
	/* save DC */
2308 2309 2310
	hPen = GetCurrentObject(hdc, OBJ_PEN);
	hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
	hFont = GetCurrentObject(hdc, OBJ_FONT);
2311

2312 2313 2314 2315 2316 2317 2318
        hRgn = CreateRectRgn(0, 0, 0, 0);
        if (!GetClipRgn(hdc, hRgn))
        {
            DeleteObject(hRgn);
            hRgn = 0;
        }

2319 2320
        old_text_color = SetTextColor(hdc, RGB(0,0,0));
        old_bk_color = SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
2321 2322 2323 2324 2325
        old_align = SetTextAlign(hdc, 0);
        old_rop2 = SetROP2(hdc, R2_COPYPEN);
        old_arcdir = SetArcDirection(hdc, AD_COUNTERCLOCKWISE);
        old_polyfill = SetPolyFillMode(hdc, ALTERNATE);
        old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE);
2326
    }
2327

2328
    info->state.mode = MM_TEXT;
2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342

    if ( IS_WIN9X() )
    {
        /* Win95 leaves the vp/win ext/org info alone */
        info->init_transform.eM11 = 1.0;
        info->init_transform.eM12 = 0.0;
        info->init_transform.eM21 = 0.0;
        info->init_transform.eM22 = 1.0;
        info->init_transform.eDx  = 0.0;
        info->init_transform.eDy  = 0.0;
    }
    else
    {
        /* WinNT combines the vp/win ext/org info into a transform */
2343 2344 2345
        double xscale, yscale;
        xscale = (double)vp_size.cx / (double)win_size.cx;
        yscale = (double)vp_size.cy / (double)win_size.cy;
2346 2347 2348 2349
        info->init_transform.eM11 = xscale;
        info->init_transform.eM12 = 0.0;
        info->init_transform.eM21 = 0.0;
        info->init_transform.eM22 = yscale;
2350 2351
        info->init_transform.eDx  = (double)vp_org.x - xscale * (double)win_org.x;
        info->init_transform.eDy  = (double)vp_org.y - yscale * (double)win_org.y;
2352 2353 2354 2355

        CombineTransform(&info->init_transform, &savedXform, &info->init_transform);
    }

2356
    if ( lpRect && WIDTH(emh->rclFrame) && HEIGHT(emh->rclFrame) )
2357
    {
2358
        double xSrcPixSize, ySrcPixSize, xscale, yscale;
2359 2360
        XFORM xform;

2361
        TRACE("rect: %d,%d - %d,%d. rclFrame: %d,%d - %d,%d\n",
2362 2363 2364 2365
           lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
           emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
           emh->rclFrame.bottom);

2366 2367 2368
        xSrcPixSize = (double) emh->szlMillimeters.cx / emh->szlDevice.cx;
        ySrcPixSize = (double) emh->szlMillimeters.cy / emh->szlDevice.cy;
        xscale = (double) WIDTH(*lpRect) * 100.0 /
2369
                 WIDTH(emh->rclFrame) * xSrcPixSize;
2370
        yscale = (double) HEIGHT(*lpRect) * 100.0 /
2371
                 HEIGHT(emh->rclFrame) * ySrcPixSize;
2372
        TRACE("xscale = %f, yscale = %f\n", xscale, yscale);
2373 2374 2375 2376 2377

        xform.eM11 = xscale;
        xform.eM12 = 0;
        xform.eM21 = 0;
        xform.eM22 = yscale;
2378 2379
        xform.eDx = (double) lpRect->left - (double) WIDTH(*lpRect) / WIDTH(emh->rclFrame) * emh->rclFrame.left;
        xform.eDy = (double) lpRect->top - (double) HEIGHT(*lpRect) / HEIGHT(emh->rclFrame) * emh->rclFrame.top;
2380 2381 2382 2383 2384

        CombineTransform(&info->init_transform, &xform, &info->init_transform);
    }

    /* WinNT resets the current vp/win org/ext */
2385
    if ( !IS_WIN9X() && hdc )
2386 2387 2388 2389 2390 2391
    {
        SetMapMode(hdc, MM_TEXT);
        SetWindowOrgEx(hdc, 0, 0, NULL);
        SetViewportOrgEx(hdc, 0, 0, NULL);
        EMF_Update_MF_Xform(hdc, info);
    }
2392 2393 2394 2395 2396 2397

    ret = TRUE;
    offset = 0;
    while(ret && offset < emh->nBytes)
    {
	emr = (ENHMETARECORD *)((char *)emh + offset);
2398 2399 2400 2401 2402

        /* In Win9x mode we update the xform if the record will produce output */
        if (hdc && IS_WIN9X() && emr_produces_output(emr->iType))
            EMF_Update_MF_Xform(hdc, info);

2403
	TRACE("Calling EnumFunc with record %s, size %d\n", get_emr_name(emr->iType), emr->nSize);
2404
	ret = (*callback)(hdc, ht, emr, emh->nHandles, (LPARAM)data);
2405
	offset += emr->nSize;
2406 2407 2408 2409 2410

        /* WinNT - update the transform (win9x updates when the next graphics
           output record is played). */
        if (hdc && !IS_WIN9X())
            EMF_Update_MF_Xform(hdc, info);
2411
    }
2412

2413 2414
    if (hdc)
    {
2415 2416 2417 2418 2419
        SetStretchBltMode(hdc, old_stretchblt);
        SetPolyFillMode(hdc, old_polyfill);
        SetArcDirection(hdc, old_arcdir);
        SetROP2(hdc, old_rop2);
        SetTextAlign(hdc, old_align);
2420 2421 2422
        SetBkColor(hdc, old_bk_color);
        SetTextColor(hdc, old_text_color);

2423
	/* restore DC */
2424 2425 2426
	SelectObject(hdc, hBrush);
	SelectObject(hdc, hPen);
	SelectObject(hdc, hFont);
2427 2428
        ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
        DeleteObject(hRgn);
2429 2430 2431 2432

	SetWorldTransform(hdc, &savedXform);
	if (savedMode)
	    SetGraphicsMode(hdc, savedMode);
2433 2434 2435 2436 2437
        SetMapMode(hdc, mapMode);
        SetWindowOrgEx(hdc, win_org.x, win_org.y, NULL);
        SetWindowExtEx(hdc, win_size.cx, win_size.cy, NULL);
        SetViewportOrgEx(hdc, vp_org.x, vp_org.y, NULL);
        SetViewportExtEx(hdc, vp_size.cx, vp_size.cy, NULL);
2438
    }
2439

2440
    for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */
2441 2442
        if( (ht->objectHandle)[i] )
	    DeleteObject( (ht->objectHandle)[i] );
2443

2444 2445 2446 2447 2448 2449
    while (info->saved_state)
    {
        EMF_dc_state *state = info->saved_state;
        info->saved_state = info->saved_state->next;
        HeapFree( GetProcessHeap(), 0, state );
    }
2450
    HeapFree( GetProcessHeap(), 0, info );
2451
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
2452 2453
}

2454
static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht,
2455 2456
						const ENHMETARECORD *emr,
						INT handles, LPARAM data)
2457 2458 2459
{
    return PlayEnhMetaFileRecord(hdc, ht, emr, handles);
}
2460

2461
/**************************************************************************
2462
 *    PlayEnhMetaFile  (GDI32.@)
2463 2464 2465 2466
 *
 *    Renders an enhanced metafile into a specified rectangle *lpRect
 *    in device context hdc.
 *
2467 2468 2469
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
2470
 */
2471
BOOL WINAPI PlayEnhMetaFile(
2472 2473 2474
       HDC hdc,           /* [in] DC to render into */
       HENHMETAFILE hmf,  /* [in] metafile to render */
       const RECT *lpRect /* [in] rectangle to place metafile inside */
2475 2476 2477 2478 2479 2480
      )
{
    return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL,
			   lpRect);
}

Alexandre Julliard's avatar
Alexandre Julliard committed
2481
/*****************************************************************************
2482
 *  DeleteEnhMetaFile (GDI32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
2483 2484
 *
 *  Deletes an enhanced metafile and frees the associated storage.
Alexandre Julliard's avatar
Alexandre Julliard committed
2485
 */
2486 2487 2488
BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
{
    return EMF_Delete_HENHMETAFILE( hmf );
Alexandre Julliard's avatar
Alexandre Julliard committed
2489 2490 2491
}

/*****************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
2492 2493 2494
 *  CopyEnhMetaFileA (GDI32.@)
 *
 * Duplicate an enhanced metafile.
Alexandre Julliard's avatar
Alexandre Julliard committed
2495
 *
2496
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
2497
 */
2498
HENHMETAFILE WINAPI CopyEnhMetaFileA(
2499
    HENHMETAFILE hmfSrc,
Alexandre Julliard's avatar
Alexandre Julliard committed
2500 2501
    LPCSTR file)
{
2502 2503 2504
    ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
    HENHMETAFILE hmfDst;

2505
    if(!emrSrc) return FALSE;
2506
    if (!file) {
2507
        emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
2508
	memcpy( emrDst, emrSrc, emrSrc->nBytes );
2509
	hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
2510
    } else {
2511
        HANDLE hFile;
2512
        DWORD w;
2513 2514
        hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0,
			     NULL, CREATE_ALWAYS, 0, 0);
2515
	WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
2516 2517 2518 2519 2520 2521 2522 2523 2524
	CloseHandle( hFile );
	/* Reopen file for reading only, so that apps can share
	   read access to the file while hmf is still valid */
        hFile = CreateFileA( file, GENERIC_READ, FILE_SHARE_READ,
			     NULL, OPEN_EXISTING, 0, 0);
	if(hFile == INVALID_HANDLE_VALUE) {
	    ERR("Can't reopen emf for reading\n");
	    return 0;
	}
2525
	hmfDst = EMF_GetEnhMetaFile( hFile );
2526
        CloseHandle( hFile );
2527 2528
    }
    return hmfDst;
Alexandre Julliard's avatar
Alexandre Julliard committed
2529 2530
}

Huw Davies's avatar
Huw Davies committed
2531
/*****************************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
2532 2533 2534
 *  CopyEnhMetaFileW (GDI32.@)
 *
 * See CopyEnhMetaFileA.
Huw Davies's avatar
Huw Davies committed
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551
 *
 *
 */
HENHMETAFILE WINAPI CopyEnhMetaFileW(
    HENHMETAFILE hmfSrc,
    LPCWSTR file)
{
    ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
    HENHMETAFILE hmfDst;

    if(!emrSrc) return FALSE;
    if (!file) {
        emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
	memcpy( emrDst, emrSrc, emrSrc->nBytes );
	hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
    } else {
        HANDLE hFile;
2552
        DWORD w;
Huw Davies's avatar
Huw Davies committed
2553 2554
        hFile = CreateFileW( file, GENERIC_WRITE | GENERIC_READ, 0,
			     NULL, CREATE_ALWAYS, 0, 0);
2555
	WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
Huw Davies's avatar
Huw Davies committed
2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570
	CloseHandle( hFile );
	/* Reopen file for reading only, so that apps can share
	   read access to the file while hmf is still valid */
        hFile = CreateFileW( file, GENERIC_READ, FILE_SHARE_READ,
			     NULL, OPEN_EXISTING, 0, 0);
	if(hFile == INVALID_HANDLE_VALUE) {
	    ERR("Can't reopen emf for reading\n");
	    return 0;
	}
	hmfDst = EMF_GetEnhMetaFile( hFile );
        CloseHandle( hFile );
    }
    return hmfDst;
}

2571

2572 2573 2574 2575 2576 2577 2578
/* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */
typedef struct tagEMF_PaletteCopy
{
   UINT cEntries;
   LPPALETTEENTRY lpPe;
} EMF_PaletteCopy;

2579
/***************************************************************
2580
 * Find the EMR_EOF record and then use it to find the
2581
 * palette entries for this enhanced metafile.
2582
 * The lpData is actually a pointer to an EMF_PaletteCopy struct
2583 2584 2585 2586 2587
 * which contains the max number of elements to copy and where
 * to copy them to.
 *
 * NOTE: To be used by GetEnhMetaFilePaletteEntries only!
 */
2588
static INT CALLBACK cbEnhPaletteCopy( HDC a,
2589 2590
                               HANDLETABLE *b,
                               const ENHMETARECORD *lpEMR,
2591
                               INT c,
2592
                               LPARAM lpData )
2593
{
2594

2595 2596
  if ( lpEMR->iType == EMR_EOF )
  {
2597
    const EMREOF *lpEof = (const EMREOF *)lpEMR;
2598
    EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData;
2599
    DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries );
2600

2601
    TRACE( "copying 0x%08x palettes\n", dwNumPalToCopy );
2602

2603
    memcpy( (LPVOID)info->lpPe,
2604
            (LPCVOID)(((LPCSTR)lpEof) + lpEof->offPalEntries),
2605 2606 2607 2608
            sizeof( *(info->lpPe) ) * dwNumPalToCopy );

    /* Update the passed data as a return code */
    info->lpPe     = NULL; /* Palettes were copied! */
2609
    info->cEntries = dwNumPalToCopy;
2610 2611 2612

    return FALSE; /* That's all we need */
  }
2613

2614 2615 2616
  return TRUE;
}

2617
/*****************************************************************************
2618 2619 2620 2621
 *  GetEnhMetaFilePaletteEntries (GDI32.@)
 *
 *  Copy the palette and report size
 *
2622
 *  BUGS: Error codes (SetLastError) are not set on failures
2623
 */
2624 2625 2626
UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
					  UINT cEntries,
					  LPPALETTEENTRY lpPe )
2627
{
2628
  ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf );
2629
  EMF_PaletteCopy infoForCallBack;
2630

2631
  TRACE( "(%p,%d,%p)\n", hEmf, cEntries, lpPe );
2632

2633 2634
  if (!enhHeader) return 0;

2635 2636
  /* First check if there are any palettes associated with
     this metafile. */
2637
  if ( enhHeader->nPalEntries == 0 ) return 0;
2638 2639

  /* Is the user requesting the number of palettes? */
2640
  if ( lpPe == NULL ) return enhHeader->nPalEntries;
2641 2642 2643

  /* Copy cEntries worth of PALETTEENTRY structs into the buffer */
  infoForCallBack.cEntries = cEntries;
2644
  infoForCallBack.lpPe     = lpPe;
2645

2646
  if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy,
2647
                         &infoForCallBack, 0 ) )
2648
      return GDI_ERROR;
2649 2650 2651 2652 2653 2654

  /* Verify that the callback executed correctly */
  if ( infoForCallBack.lpPe != NULL )
  {
     /* Callback proc had error! */
     ERR( "cbEnhPaletteCopy didn't execute correctly\n" );
2655
     return GDI_ERROR;
2656 2657
  }

2658
  return infoForCallBack.cEntries;
2659 2660
}

2661 2662 2663 2664 2665 2666 2667 2668 2669 2670
typedef struct gdi_mf_comment
{
    DWORD ident;
    DWORD iComment;
    DWORD nVersion;
    DWORD nChecksum;
    DWORD fFlags;
    DWORD cbWinMetaFile;
} gdi_mf_comment;

2671
/******************************************************************
2672
 *         SetWinMetaFileBits   (GDI32.@)
2673
 *
2674
 *         Translate from old style to new style.
2675
 *
2676
 */
2677
HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
2678
					   CONST BYTE *lpbBuffer,
2679 2680
					   HDC hdcRef,
					   CONST METAFILEPICT *lpmfp
2681
					   )
2682
{
Jon Griffiths's avatar
Jon Griffiths committed
2683
    static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' };
2684 2685 2686
    HMETAFILE hmf = NULL;
    HENHMETAFILE ret = NULL;
    HDC hdc = NULL, hdcdisp = NULL;
2687
    RECT rc, *prcFrame = NULL;
2688
    LONG mm, xExt, yExt;
2689
    INT horzsize, vertsize, horzres, vertres;
2690

2691
    TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp);
2692

2693 2694 2695 2696
    hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer);
    if(!hmf)
    {
        WARN("SetMetaFileBitsEx failed\n");
2697
        return NULL;
2698
    }
2699

2700
    if(!hdcRef)
Jon Griffiths's avatar
Jon Griffiths committed
2701
        hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL);
2702

2703
    if (lpmfp)
2704
    {
2705
        TRACE("mm = %d %dx%d\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt);
2706 2707 2708 2709 2710 2711

        mm = lpmfp->mm;
        xExt = lpmfp->xExt;
        yExt = lpmfp->yExt;
    }
    else
2712
    {
2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737
        TRACE("lpmfp == NULL\n");

        /* Use the whole device surface */
        mm = MM_ANISOTROPIC;
        xExt = 0;
        yExt = 0;
    }

    if (mm == MM_ISOTROPIC || mm == MM_ANISOTROPIC)
    {
        if (xExt < 0 || yExt < 0)
        {
          /* Use the whole device surface */
          xExt = 0;
          yExt = 0;
        }

        /* Use the x and y extents as the frame box */
        if (xExt && yExt)
        {
            rc.left = rc.top = 0;
            rc.right = xExt;
            rc.bottom = yExt;
            prcFrame = &rc;
        }
2738
    }
2739

2740 2741
    if(!(hdc = CreateEnhMetaFileW(hdcRef, NULL, prcFrame, NULL)))
    {
2742
        ERR("CreateEnhMetaFile failed\n");
2743
        goto end;
2744
    }
2745

2746 2747 2748 2749
    /*
     * Write the original METAFILE into the enhanced metafile.
     * It is encapsulated in a GDICOMMENT_WINDOWS_METAFILE record.
     */
2750
    if (mm != MM_TEXT)
2751
    {
2752 2753
        gdi_mf_comment *mfcomment;
        UINT mfcomment_size;
2754

2755 2756 2757
        mfcomment_size = sizeof (gdi_mf_comment) + cbBuffer;
        mfcomment = HeapAlloc(GetProcessHeap(), 0, mfcomment_size);
        if (mfcomment)
2758
        {
2759 2760 2761 2762 2763 2764 2765 2766 2767
            mfcomment->ident = GDICOMMENT_IDENTIFIER;
            mfcomment->iComment = GDICOMMENT_WINDOWS_METAFILE;
            mfcomment->nVersion = 0x00000300;
            mfcomment->nChecksum = 0; /* FIXME */
            mfcomment->fFlags = 0;
            mfcomment->cbWinMetaFile = cbBuffer;
            memcpy(&mfcomment[1], lpbBuffer, cbBuffer);
            GdiComment(hdc, mfcomment_size, (BYTE*) mfcomment);
            HeapFree(GetProcessHeap(), 0, mfcomment);
2768
        }
2769 2770
        SetMapMode(hdc, mm);
    }
2771

2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782

    horzsize = GetDeviceCaps(hdcRef, HORZSIZE);
    vertsize = GetDeviceCaps(hdcRef, VERTSIZE);
    horzres = GetDeviceCaps(hdcRef, HORZRES);
    vertres = GetDeviceCaps(hdcRef, VERTRES);

    if (!xExt || !yExt)
    {
        /* Use the whole device surface */
       xExt = horzres;
       yExt = vertres;
2783
    }
2784 2785 2786 2787 2788 2789 2790 2791 2792
    else
    {
        xExt = MulDiv(xExt, horzres, 100 * horzsize);
        yExt = MulDiv(yExt, vertres, 100 * vertsize);
    }

    /* set the initial viewport:window ratio as 1:1 */
    SetViewportExtEx(hdc, xExt, yExt, NULL);
    SetWindowExtEx(hdc,   xExt, yExt, NULL);
2793

2794
    PlayMetaFile(hdc, hmf);
2795

2796
    ret = CloseEnhMetaFile(hdc);
2797
end:
2798
    if (hdcdisp) DeleteDC(hdcdisp);
2799 2800
    DeleteMetaFile(hmf);
    return ret;
2801
}