- Implement CCM_{GET|SET}COLORSCHEME.
[wine] / objects / enhmetafile.c
1 /*
2  * Enhanced metafile functions
3  * Copyright 1998 Douglas Ridgway
4  *           1999 Huw D M Davies 
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * NOTES:
21  *
22  * The enhanced format consists of the following elements: 
23  *
24  *    A header 
25  *    A table of handles to GDI objects 
26  *    An array of metafile records 
27  *    A private palette 
28  *
29  * 
30  *  The standard format consists of a header and an array of metafile records. 
31  *
32  */ 
33
34 #include <string.h>
35 #include <assert.h>
36 #include "winnls.h"
37 #include "winbase.h"
38 #include "wingdi.h"
39 #include "winerror.h"
40 #include "wine/debug.h"
41 #include "metafile.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
44
45 typedef struct
46 {
47     GDIOBJHDR      header;
48     ENHMETAHEADER  *emh;
49     BOOL           on_disk;   /* true if metafile is on disk */
50 } ENHMETAFILEOBJ;
51
52
53 /****************************************************************************
54  *          EMF_Create_HENHMETAFILE
55  */
56 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, BOOL on_disk )
57 {
58     HENHMETAFILE hmf = 0;
59     ENHMETAFILEOBJ *metaObj = GDI_AllocObject( sizeof(ENHMETAFILEOBJ),
60                                                ENHMETAFILE_MAGIC, &hmf );
61     if (metaObj)
62     {
63         metaObj->emh = emh;
64         metaObj->on_disk = on_disk;
65         GDI_ReleaseObj( hmf );
66     }
67     return hmf;
68 }
69
70 /****************************************************************************
71  *          EMF_Delete_HENHMETAFILE
72  */
73 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
74 {
75     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf,
76                                                            ENHMETAFILE_MAGIC );
77     if(!metaObj) return FALSE;
78
79     if(metaObj->on_disk)
80         UnmapViewOfFile( metaObj->emh );
81     else
82         HeapFree( GetProcessHeap(), 0, metaObj->emh );
83     return GDI_FreeObject( hmf, metaObj );
84 }
85
86 /******************************************************************
87  *         EMF_GetEnhMetaHeader
88  *
89  * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
90  */
91 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
92 {
93     ENHMETAHEADER *ret = NULL;
94     ENHMETAFILEOBJ *metaObj = (ENHMETAFILEOBJ *)GDI_GetObjPtr( hmf, ENHMETAFILE_MAGIC );
95     TRACE("hmf %04x -> enhmetaObj %p\n", hmf, metaObj);
96     if (metaObj)
97     {
98         ret = metaObj->emh;
99         GDI_ReleaseObj( hmf );
100     }
101     return ret;
102 }
103
104 /*****************************************************************************
105  *         EMF_GetEnhMetaFile
106  *
107  */
108 static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
109 {
110     ENHMETAHEADER *emh;
111     HANDLE hMapping;
112     
113     hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
114     emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
115     CloseHandle( hMapping );
116
117     if (!emh) return 0;
118
119     if (emh->iType != EMR_HEADER || emh->dSignature != ENHMETA_SIGNATURE) {
120         WARN("Invalid emf header type 0x%08lx sig 0x%08lx.\n",
121              emh->iType, emh->dSignature);
122         UnmapViewOfFile( emh );
123         return 0;
124     }
125     return EMF_Create_HENHMETAFILE( emh, TRUE );
126 }
127
128
129 /*****************************************************************************
130  *          GetEnhMetaFileA (GDI32.@)
131  *
132  *
133  */
134 HENHMETAFILE WINAPI GetEnhMetaFileA( 
135              LPCSTR lpszMetaFile  /* [in] filename of enhanced metafile */
136     )
137 {
138     HENHMETAFILE hmf;
139     HANDLE hFile;
140
141     hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
142                         OPEN_EXISTING, 0, 0);
143     if (hFile == INVALID_HANDLE_VALUE) {
144         WARN("could not open %s\n", lpszMetaFile);
145         return 0;
146     }
147     hmf = EMF_GetEnhMetaFile( hFile );
148     CloseHandle( hFile );
149     return hmf;
150 }
151
152 /*****************************************************************************
153  *          GetEnhMetaFileW  (GDI32.@)
154  */
155 HENHMETAFILE WINAPI GetEnhMetaFileW(
156              LPCWSTR lpszMetaFile)  /* [in] filename of enhanced metafile */ 
157 {
158     HENHMETAFILE hmf;
159     HANDLE hFile;
160
161     hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
162                         OPEN_EXISTING, 0, 0);
163     if (hFile == INVALID_HANDLE_VALUE) {
164         WARN("could not open %s\n", debugstr_w(lpszMetaFile));
165         return 0;
166     }
167     hmf = EMF_GetEnhMetaFile( hFile );
168     CloseHandle( hFile );
169     return hmf;
170 }
171
172 /*****************************************************************************
173  *        GetEnhMetaFileHeader  (GDI32.@)
174  *
175  *  If buf is NULL, returns the size of buffer required.
176  *  Otherwise, copy up to bufsize bytes of enhanced metafile header into 
177  *  buf.
178  */
179 UINT WINAPI GetEnhMetaFileHeader( 
180        HENHMETAFILE hmf,   /* [in] enhanced metafile */
181        UINT bufsize,       /* [in] size of buffer */
182        LPENHMETAHEADER buf /* [out] buffer */ 
183     )
184 {
185     LPENHMETAHEADER emh;
186     UINT size;
187
188     emh = EMF_GetEnhMetaHeader(hmf);
189     if(!emh) return FALSE;
190     size = emh->nSize;
191     if (!buf) return size;
192     size = min(size, bufsize);
193     memmove(buf, emh, size);
194     return size;
195 }
196
197
198 /*****************************************************************************
199  *          GetEnhMetaFileDescriptionA  (GDI32.@)
200  */
201 UINT WINAPI GetEnhMetaFileDescriptionA( 
202        HENHMETAFILE hmf, /* [in] enhanced metafile */
203        UINT size,        /* [in] size of buf */ 
204        LPSTR buf         /* [out] buffer to receive description */
205     )
206 {
207      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
208      DWORD len;
209      WCHAR *descrW;
210
211      if(!emh) return FALSE;
212      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
213      descrW = (WCHAR *) ((char *) emh + emh->offDescription);
214      len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL );
215
216      if (!buf || !size ) return len;
217
218      len = min( size, len );
219      WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL );
220      return len;
221 }
222
223 /*****************************************************************************
224  *          GetEnhMetaFileDescriptionW  (GDI32.@)
225  *
226  *  Copies the description string of an enhanced metafile into a buffer 
227  *  _buf_.
228  *
229  *  If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
230  *  number of characters copied.
231  */
232 UINT WINAPI GetEnhMetaFileDescriptionW( 
233        HENHMETAFILE hmf, /* [in] enhanced metafile */
234        UINT size,        /* [in] size of buf */ 
235        LPWSTR buf        /* [out] buffer to receive description */
236     )
237 {
238      LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
239
240      if(!emh) return FALSE;
241      if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
242      if (!buf || !size ) return emh->nDescription;
243
244      memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR));
245      return min(size, emh->nDescription);
246 }
247
248 /****************************************************************************
249  *    SetEnhMetaFileBits (GDI32.@)
250  *
251  *  Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
252  */
253 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
254 {
255     ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
256     memmove(emh, buf, bufsize);
257     return EMF_Create_HENHMETAFILE( emh, FALSE );
258 }
259
260 /*****************************************************************************
261  *  GetEnhMetaFileBits (GDI32.@)
262  *
263  */
264 UINT WINAPI GetEnhMetaFileBits(
265     HENHMETAFILE hmf, 
266     UINT bufsize, 
267     LPBYTE buf  
268
269 {
270     LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf );
271     UINT size;
272
273     if(!emh) return 0;
274
275     size = emh->nBytes;
276     if( buf == NULL ) return size;
277
278     size = min( size, bufsize );
279     memmove(buf, emh, size);
280     return size;
281 }
282
283 /*****************************************************************************
284  *           PlayEnhMetaFileRecord  (GDI32.@)
285  *
286  *  Render a single enhanced metafile record in the device context hdc.
287  *
288  *  RETURNS
289  *    TRUE (non zero) on success, FALSE on error.
290  *  BUGS
291  *    Many unimplemented records.
292  *    No error handling on record play failures (ie checking return codes)
293  */
294 BOOL WINAPI PlayEnhMetaFileRecord( 
295      HDC hdc,                   /* [in] device context in which to render EMF record */
296      LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */
297      const ENHMETARECORD *mr,   /* [in] EMF record to render */
298      UINT handles               /* [in] size of handle array */
299      ) 
300 {
301   int type;
302   TRACE(
303         "hdc = %08x, handletable = %p, record = %p, numHandles = %d\n", 
304           hdc, handletable, mr, handles);
305   if (!mr) return FALSE;
306
307   type = mr->iType;
308
309   TRACE(" type=%d\n", type);
310   switch(type) 
311     {
312     case EMR_HEADER:
313       break;
314     case EMR_EOF:
315       break;
316     case EMR_GDICOMMENT:
317       {
318         PEMRGDICOMMENT lpGdiComment = (PEMRGDICOMMENT)mr;
319         /* In an enhanced metafile, there can be both public and private GDI comments */
320         GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
321         break;
322       } 
323     case EMR_SETMAPMODE:
324       {
325         PEMRSETMAPMODE pSetMapMode = (PEMRSETMAPMODE) mr;
326         SetMapMode(hdc, pSetMapMode->iMode);
327         break;
328       }
329     case EMR_SETBKMODE:
330       {
331         PEMRSETBKMODE pSetBkMode = (PEMRSETBKMODE) mr;
332         SetBkMode(hdc, pSetBkMode->iMode);
333         break;
334       }
335     case EMR_SETBKCOLOR:
336       {
337         PEMRSETBKCOLOR pSetBkColor = (PEMRSETBKCOLOR) mr;
338         SetBkColor(hdc, pSetBkColor->crColor);
339         break;
340       }
341     case EMR_SETPOLYFILLMODE:
342       {
343         PEMRSETPOLYFILLMODE pSetPolyFillMode = (PEMRSETPOLYFILLMODE) mr;
344         SetPolyFillMode(hdc, pSetPolyFillMode->iMode);
345         break;
346       }
347     case EMR_SETROP2:
348       {
349         PEMRSETROP2 pSetROP2 = (PEMRSETROP2) mr;
350         SetROP2(hdc, pSetROP2->iMode);
351         break;
352       }
353     case EMR_SETSTRETCHBLTMODE:
354       {
355         PEMRSETSTRETCHBLTMODE pSetStretchBltMode = (PEMRSETSTRETCHBLTMODE) mr;
356         SetStretchBltMode(hdc, pSetStretchBltMode->iMode);
357         break;
358       }
359     case EMR_SETTEXTALIGN:
360       {
361         PEMRSETTEXTALIGN pSetTextAlign = (PEMRSETTEXTALIGN) mr;
362         SetTextAlign(hdc, pSetTextAlign->iMode);
363         break;
364       }
365     case EMR_SETTEXTCOLOR:
366       {
367         PEMRSETTEXTCOLOR pSetTextColor = (PEMRSETTEXTCOLOR) mr;
368         SetTextColor(hdc, pSetTextColor->crColor);
369         break;
370       }
371     case EMR_SAVEDC:
372       {
373         SaveDC(hdc);
374         break;
375       }
376     case EMR_RESTOREDC:
377       {
378         PEMRRESTOREDC pRestoreDC = (PEMRRESTOREDC) mr;
379         RestoreDC(hdc, pRestoreDC->iRelative);
380         break;
381       }
382     case EMR_INTERSECTCLIPRECT:
383       {
384         PEMRINTERSECTCLIPRECT pClipRect = (PEMRINTERSECTCLIPRECT) mr;
385         IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top,
386                           pClipRect->rclClip.right, pClipRect->rclClip.bottom);
387         break;
388       }
389     case EMR_SELECTOBJECT:
390       {
391         PEMRSELECTOBJECT pSelectObject = (PEMRSELECTOBJECT) mr;
392         if( pSelectObject->ihObject & 0x80000000 ) {
393           /* High order bit is set - it's a stock object
394            * Strip the high bit to get the index.
395            * See MSDN article Q142319
396            */
397           SelectObject( hdc, GetStockObject( pSelectObject->ihObject &
398                                              0x7fffffff ) );
399         } else {
400           /* High order bit wasn't set - not a stock object
401            */
402               SelectObject( hdc,
403                         (handletable->objectHandle)[pSelectObject->ihObject] );
404         }
405         break;
406       }
407     case EMR_DELETEOBJECT:
408       {
409         PEMRDELETEOBJECT pDeleteObject = (PEMRDELETEOBJECT) mr;
410         DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]);
411         (handletable->objectHandle)[pDeleteObject->ihObject] = 0;
412         break;
413       }
414     case EMR_SETWINDOWORGEX:
415       {
416           /*
417            * FIXME: The call to SetWindowOrgEx prevents EMFs from being scrolled
418            *        by an application. This is very BAD!!!
419            */
420 #if 0
421         PEMRSETWINDOWORGEX pSetWindowOrgEx = (PEMRSETWINDOWORGEX) mr;
422         SetWindowOrgEx(hdc, pSetWindowOrgEx->ptlOrigin.x,
423                        pSetWindowOrgEx->ptlOrigin.y, NULL);
424 #endif
425         break;
426       }
427     case EMR_SETWINDOWEXTEX:
428       {
429         PEMRSETWINDOWEXTEX pSetWindowExtEx = (PEMRSETWINDOWEXTEX) mr;
430         SetWindowExtEx(hdc, pSetWindowExtEx->szlExtent.cx,
431                        pSetWindowExtEx->szlExtent.cy, NULL);
432         break;
433       }
434     case EMR_SETVIEWPORTORGEX:
435       {
436         PEMRSETVIEWPORTORGEX pSetViewportOrgEx = (PEMRSETVIEWPORTORGEX) mr;
437         SetViewportOrgEx(hdc, pSetViewportOrgEx->ptlOrigin.x,
438                          pSetViewportOrgEx->ptlOrigin.y, NULL);
439         break;
440       }
441     case EMR_SETVIEWPORTEXTEX:
442       {
443         PEMRSETVIEWPORTEXTEX pSetViewportExtEx = (PEMRSETVIEWPORTEXTEX) mr;
444         SetViewportExtEx(hdc, pSetViewportExtEx->szlExtent.cx,
445                          pSetViewportExtEx->szlExtent.cy, NULL);
446         break;
447       }
448     case EMR_CREATEPEN:
449       {
450         PEMRCREATEPEN pCreatePen = (PEMRCREATEPEN) mr;
451         (handletable->objectHandle)[pCreatePen->ihPen] = 
452           CreatePenIndirect(&pCreatePen->lopn);
453         break;
454       }
455     case EMR_EXTCREATEPEN:
456       {
457         PEMREXTCREATEPEN pPen = (PEMREXTCREATEPEN) mr;
458         LOGBRUSH lb;
459         lb.lbStyle = pPen->elp.elpBrushStyle;
460         lb.lbColor = pPen->elp.elpColor;
461         lb.lbHatch = pPen->elp.elpHatch;
462
463         if(pPen->offBmi || pPen->offBits)
464           FIXME("EMR_EXTCREATEPEN: Need to copy brush bitmap\n");
465
466         (handletable->objectHandle)[pPen->ihPen] = 
467           ExtCreatePen(pPen->elp.elpPenStyle, pPen->elp.elpWidth, &lb, 
468                        pPen->elp.elpNumEntries, pPen->elp.elpStyleEntry);
469         break;
470       }
471     case EMR_CREATEBRUSHINDIRECT:
472       {
473         PEMRCREATEBRUSHINDIRECT pBrush = (PEMRCREATEBRUSHINDIRECT) mr;
474         (handletable->objectHandle)[pBrush->ihBrush] = 
475           CreateBrushIndirect(&pBrush->lb);
476         break;
477       }
478     case EMR_EXTCREATEFONTINDIRECTW:
479       {
480         PEMREXTCREATEFONTINDIRECTW pFont = (PEMREXTCREATEFONTINDIRECTW) mr;
481         (handletable->objectHandle)[pFont->ihFont] = 
482           CreateFontIndirectW(&pFont->elfw.elfLogFont);
483         break;
484       }
485     case EMR_MOVETOEX:
486       {
487         PEMRMOVETOEX pMoveToEx = (PEMRMOVETOEX) mr;
488         MoveToEx(hdc, pMoveToEx->ptl.x, pMoveToEx->ptl.y, NULL);
489         break;
490       }
491     case EMR_LINETO:
492       {
493         PEMRLINETO pLineTo = (PEMRLINETO) mr;
494         LineTo(hdc, pLineTo->ptl.x, pLineTo->ptl.y);
495         break;
496       }
497     case EMR_RECTANGLE:
498       {
499         PEMRRECTANGLE pRect = (PEMRRECTANGLE) mr;
500         Rectangle(hdc, pRect->rclBox.left, pRect->rclBox.top,
501                   pRect->rclBox.right, pRect->rclBox.bottom);
502         break;
503       }
504     case EMR_ELLIPSE:
505       {
506         PEMRELLIPSE pEllipse = (PEMRELLIPSE) mr;
507         Ellipse(hdc, pEllipse->rclBox.left, pEllipse->rclBox.top,
508                 pEllipse->rclBox.right, pEllipse->rclBox.bottom);
509         break;
510       }
511     case EMR_POLYGON16:
512       {
513         PEMRPOLYGON16 pPoly = (PEMRPOLYGON16) mr;
514         /* Shouldn't use Polygon16 since pPoly->cpts is DWORD */
515         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
516                                 pPoly->cpts * sizeof(POINT) );
517         DWORD i;
518         for(i = 0; i < pPoly->cpts; i++)
519           CONV_POINT16TO32(pPoly->apts + i, pts + i);
520         Polygon(hdc, pts, pPoly->cpts);
521         HeapFree( GetProcessHeap(), 0, pts );
522         break;
523       }
524     case EMR_POLYLINE16:
525       {
526         PEMRPOLYLINE16 pPoly = (PEMRPOLYLINE16) mr;
527         /* Shouldn't use Polyline16 since pPoly->cpts is DWORD */
528         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
529                                 pPoly->cpts * sizeof(POINT) );
530         DWORD i;
531         for(i = 0; i < pPoly->cpts; i++)
532           CONV_POINT16TO32(pPoly->apts + i, pts + i);
533         Polyline(hdc, pts, pPoly->cpts);
534         HeapFree( GetProcessHeap(), 0, pts );
535         break;
536       }
537     case EMR_POLYLINETO16:
538       {
539         PEMRPOLYLINETO16 pPoly = (PEMRPOLYLINETO16) mr;
540         /* Shouldn't use PolylineTo16 since pPoly->cpts is DWORD */
541         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
542                                 pPoly->cpts * sizeof(POINT) );
543         DWORD i;
544         for(i = 0; i < pPoly->cpts; i++)
545           CONV_POINT16TO32(pPoly->apts + i, pts + i);
546         PolylineTo(hdc, pts, pPoly->cpts);
547         HeapFree( GetProcessHeap(), 0, pts );
548         break;
549       }
550     case EMR_POLYBEZIER16:
551       {
552         PEMRPOLYBEZIER16 pPoly = (PEMRPOLYBEZIER16) mr;
553         /* Shouldn't use PolyBezier16 since pPoly->cpts is DWORD */
554         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
555                                 pPoly->cpts * sizeof(POINT) );
556         DWORD i;
557         for(i = 0; i < pPoly->cpts; i++)
558           CONV_POINT16TO32(pPoly->apts + i, pts + i);
559         PolyBezier(hdc, pts, pPoly->cpts);
560         HeapFree( GetProcessHeap(), 0, pts );
561         break;
562       }
563     case EMR_POLYBEZIERTO16:
564       {
565         PEMRPOLYBEZIERTO16 pPoly = (PEMRPOLYBEZIERTO16) mr;
566         /* Shouldn't use PolyBezierTo16 since pPoly->cpts is DWORD */
567         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
568                                 pPoly->cpts * sizeof(POINT) );
569         DWORD i;
570         for(i = 0; i < pPoly->cpts; i++)
571           CONV_POINT16TO32(pPoly->apts + i, pts + i);
572         PolyBezierTo(hdc, pts, pPoly->cpts);
573         HeapFree( GetProcessHeap(), 0, pts );
574         break;
575       }
576     case EMR_POLYPOLYGON16:
577       {
578         PEMRPOLYPOLYGON16 pPolyPoly = (PEMRPOLYPOLYGON16) mr;
579         /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
580            pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
581
582         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
583                                 pPolyPoly->cpts * sizeof(POINT) );
584         DWORD i;
585         for(i = 0; i < pPolyPoly->cpts; i++)
586           CONV_POINT16TO32((POINT16*) (pPolyPoly->aPolyCounts +
587                                       pPolyPoly->nPolys) + i, pts + i);
588
589         PolyPolygon(hdc, pts, (INT*)pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
590         HeapFree( GetProcessHeap(), 0, pts );
591         break;
592       }
593     case EMR_POLYPOLYLINE16:
594       {
595         PEMRPOLYPOLYLINE16 pPolyPoly = (PEMRPOLYPOLYLINE16) mr;
596         /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
597            pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
598
599         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
600                                 pPolyPoly->cpts * sizeof(POINT) );
601         DWORD i;
602         for(i = 0; i < pPolyPoly->cpts; i++)
603           CONV_POINT16TO32((POINT16*) (pPolyPoly->aPolyCounts +
604                                       pPolyPoly->nPolys) + i, pts + i);
605
606         PolyPolyline(hdc, pts, pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
607         HeapFree( GetProcessHeap(), 0, pts );
608         break;
609       }
610
611     case EMR_STRETCHDIBITS:
612       {
613         EMRSTRETCHDIBITS *pStretchDIBits = (EMRSTRETCHDIBITS *)mr;
614
615         StretchDIBits(hdc,
616                       pStretchDIBits->xDest,
617                       pStretchDIBits->yDest,
618                       pStretchDIBits->cxDest,
619                       pStretchDIBits->cyDest,
620                       pStretchDIBits->xSrc,
621                       pStretchDIBits->ySrc,
622                       pStretchDIBits->cxSrc,
623                       pStretchDIBits->cySrc,
624                       (BYTE *)mr + pStretchDIBits->offBitsSrc,
625                       (const BITMAPINFO *)((BYTE *)mr + pStretchDIBits->offBmiSrc),
626                       pStretchDIBits->iUsageSrc,
627                       pStretchDIBits->dwRop);
628         break;
629       }
630
631     case EMR_EXTTEXTOUTA:
632     {
633         PEMREXTTEXTOUTA pExtTextOutA = (PEMREXTTEXTOUTA)mr;
634         RECT rc;
635
636         rc.left = pExtTextOutA->emrtext.rcl.left;
637         rc.top = pExtTextOutA->emrtext.rcl.top;
638         rc.right = pExtTextOutA->emrtext.rcl.right;
639         rc.bottom = pExtTextOutA->emrtext.rcl.bottom;
640         ExtTextOutA(hdc, pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
641             pExtTextOutA->emrtext.fOptions, &rc,
642             (LPSTR)((BYTE *)mr + pExtTextOutA->emrtext.offString), pExtTextOutA->emrtext.nChars,
643             (INT *)((BYTE *)mr + pExtTextOutA->emrtext.offDx));
644         break;
645     }
646
647     case EMR_EXTTEXTOUTW:
648     {
649         PEMREXTTEXTOUTW pExtTextOutW = (PEMREXTTEXTOUTW)mr;
650         RECT rc;
651
652         rc.left = pExtTextOutW->emrtext.rcl.left;
653         rc.top = pExtTextOutW->emrtext.rcl.top;
654         rc.right = pExtTextOutW->emrtext.rcl.right;
655         rc.bottom = pExtTextOutW->emrtext.rcl.bottom;
656         ExtTextOutW(hdc, pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
657             pExtTextOutW->emrtext.fOptions, &rc,
658             (LPWSTR)((BYTE *)mr + pExtTextOutW->emrtext.offString), pExtTextOutW->emrtext.nChars,
659             (INT *)((BYTE *)mr + pExtTextOutW->emrtext.offDx));
660         break;
661     }
662
663     case EMR_CREATEPALETTE:
664       {
665         PEMRCREATEPALETTE lpCreatePal = (PEMRCREATEPALETTE)mr;
666
667         (handletable->objectHandle)[ lpCreatePal->ihPal ] = 
668                 CreatePalette( &lpCreatePal->lgpl );
669
670         break;
671       }
672
673     case EMR_SELECTPALETTE:
674       {
675         PEMRSELECTPALETTE lpSelectPal = (PEMRSELECTPALETTE)mr;
676
677         if( lpSelectPal->ihPal & 0x80000000 ) {
678                 SelectPalette( hdc, GetStockObject(lpSelectPal->ihPal & 0x7fffffff), TRUE);
679         } else {
680         (handletable->objectHandle)[ lpSelectPal->ihPal ] =
681                 SelectPalette( hdc, (handletable->objectHandle)[lpSelectPal->ihPal], TRUE);
682         }
683         break;
684       }
685
686     case EMR_REALIZEPALETTE:
687       {
688         RealizePalette( hdc );
689         break;
690       }
691
692     case EMR_EXTSELECTCLIPRGN:
693       {
694         PEMREXTSELECTCLIPRGN lpRgn = (PEMREXTSELECTCLIPRGN)mr;
695         HRGN hRgn = ExtCreateRegion(NULL, lpRgn->cbRgnData, (RGNDATA *)lpRgn->RgnData);
696         ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode));
697         /* ExtSelectClipRgn created a copy of the region */
698         DeleteObject(hRgn);
699         break;
700       }
701
702     case EMR_SETMETARGN:
703       {
704         SetMetaRgn( hdc );
705         break;
706       }
707
708     case EMR_SETWORLDTRANSFORM:
709       {
710         PEMRSETWORLDTRANSFORM lpXfrm = (PEMRSETWORLDTRANSFORM)mr;
711         SetWorldTransform( hdc, &lpXfrm->xform );
712         break;
713       }
714
715     case EMR_POLYBEZIER:
716       {
717         PEMRPOLYBEZIER lpPolyBez = (PEMRPOLYBEZIER)mr; 
718         PolyBezier(hdc, (const LPPOINT)lpPolyBez->aptl, (UINT)lpPolyBez->cptl);
719         break;
720       }
721
722     case EMR_POLYGON:
723       {
724         PEMRPOLYGON lpPoly = (PEMRPOLYGON)mr;
725         Polygon( hdc, (const LPPOINT)lpPoly->aptl, (UINT)lpPoly->cptl );
726         break;
727       }
728
729     case EMR_POLYLINE:
730       {
731         PEMRPOLYLINE lpPolyLine = (PEMRPOLYLINE)mr;
732         Polyline(hdc, (const LPPOINT)lpPolyLine->aptl, (UINT)lpPolyLine->cptl);
733         break; 
734       }
735
736     case EMR_POLYBEZIERTO:
737       {
738         PEMRPOLYBEZIERTO lpPolyBezierTo = (PEMRPOLYBEZIERTO)mr;
739         PolyBezierTo( hdc, (const LPPOINT)lpPolyBezierTo->aptl,
740                       (UINT)lpPolyBezierTo->cptl );
741         break; 
742       }
743
744     case EMR_POLYLINETO:
745       {
746         PEMRPOLYLINETO lpPolyLineTo = (PEMRPOLYLINETO)mr;
747         PolylineTo( hdc, (const LPPOINT)lpPolyLineTo->aptl,
748                     (UINT)lpPolyLineTo->cptl );
749         break;
750       }
751
752     case EMR_POLYPOLYLINE:
753       {
754         PEMRPOLYPOLYLINE pPolyPolyline = (PEMRPOLYPOLYLINE) mr;
755         /* NB Points at pPolyPolyline->aPolyCounts + pPolyPolyline->nPolys */
756
757         PolyPolyline(hdc, (LPPOINT)(pPolyPolyline->aPolyCounts +
758                                     pPolyPolyline->nPolys), 
759                      pPolyPolyline->aPolyCounts, 
760                      pPolyPolyline->nPolys ); 
761
762         break;
763       }
764
765     case EMR_POLYPOLYGON:
766       {
767         PEMRPOLYPOLYGON pPolyPolygon = (PEMRPOLYPOLYGON) mr;
768
769         /* NB Points at pPolyPolygon->aPolyCounts + pPolyPolygon->nPolys */
770
771         PolyPolygon(hdc, (LPPOINT)(pPolyPolygon->aPolyCounts +
772                                    pPolyPolygon->nPolys),
773                     (INT*)pPolyPolygon->aPolyCounts, pPolyPolygon->nPolys );
774         break;
775       }
776
777     case EMR_SETBRUSHORGEX:
778       {
779         PEMRSETBRUSHORGEX lpSetBrushOrgEx = (PEMRSETBRUSHORGEX)mr;
780
781         SetBrushOrgEx( hdc, 
782                        (INT)lpSetBrushOrgEx->ptlOrigin.x, 
783                        (INT)lpSetBrushOrgEx->ptlOrigin.y, 
784                        NULL );
785
786         break;
787       }
788  
789     case EMR_SETPIXELV:
790       {
791         PEMRSETPIXELV lpSetPixelV = (PEMRSETPIXELV)mr;
792
793         SetPixelV( hdc, 
794                    (INT)lpSetPixelV->ptlPixel.x, 
795                    (INT)lpSetPixelV->ptlPixel.y, 
796                    lpSetPixelV->crColor );
797
798         break;
799       }
800
801     case EMR_SETMAPPERFLAGS:
802       {
803         PEMRSETMAPPERFLAGS lpSetMapperFlags = (PEMRSETMAPPERFLAGS)mr;
804    
805         SetMapperFlags( hdc, lpSetMapperFlags->dwFlags );
806
807         break;
808       }
809
810     case EMR_SETCOLORADJUSTMENT:
811       {
812         PEMRSETCOLORADJUSTMENT lpSetColorAdjust = (PEMRSETCOLORADJUSTMENT)mr; 
813
814         SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment );
815
816         break;
817       }
818
819     case EMR_OFFSETCLIPRGN:
820       {
821         PEMROFFSETCLIPRGN lpOffsetClipRgn = (PEMROFFSETCLIPRGN)mr;
822
823         OffsetClipRgn( hdc, 
824                        (INT)lpOffsetClipRgn->ptlOffset.x,
825                        (INT)lpOffsetClipRgn->ptlOffset.y );
826
827         break;
828       } 
829
830     case EMR_EXCLUDECLIPRECT:
831       {
832         PEMREXCLUDECLIPRECT lpExcludeClipRect = (PEMREXCLUDECLIPRECT)mr;
833
834         ExcludeClipRect( hdc, 
835                          lpExcludeClipRect->rclClip.left, 
836                          lpExcludeClipRect->rclClip.top, 
837                          lpExcludeClipRect->rclClip.right, 
838                          lpExcludeClipRect->rclClip.bottom  );
839
840          break;
841       }
842
843     case EMR_SCALEVIEWPORTEXTEX:
844       {
845         PEMRSCALEVIEWPORTEXTEX lpScaleViewportExtEx = (PEMRSCALEVIEWPORTEXTEX)mr;
846
847         ScaleViewportExtEx( hdc, 
848                             lpScaleViewportExtEx->xNum,
849                             lpScaleViewportExtEx->xDenom,
850                             lpScaleViewportExtEx->yNum,
851                             lpScaleViewportExtEx->yDenom,
852                             NULL );
853      
854         break;
855       }
856  
857     case EMR_SCALEWINDOWEXTEX:
858       {
859         PEMRSCALEWINDOWEXTEX lpScaleWindowExtEx = (PEMRSCALEWINDOWEXTEX)mr;
860
861         ScaleWindowExtEx( hdc,
862                           lpScaleWindowExtEx->xNum,
863                           lpScaleWindowExtEx->xDenom,
864                           lpScaleWindowExtEx->yNum,
865                           lpScaleWindowExtEx->yDenom, 
866                           NULL );
867
868         break;
869       }
870
871     case EMR_MODIFYWORLDTRANSFORM:
872       {
873         PEMRMODIFYWORLDTRANSFORM lpModifyWorldTrans = (PEMRMODIFYWORLDTRANSFORM)mr;
874
875         ModifyWorldTransform( hdc, &lpModifyWorldTrans->xform,
876                               lpModifyWorldTrans->iMode );
877
878         break;
879       }
880
881     case EMR_ANGLEARC:
882       {
883         PEMRANGLEARC lpAngleArc = (PEMRANGLEARC)mr; 
884
885         AngleArc( hdc, 
886                  (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y,
887                  lpAngleArc->nRadius, lpAngleArc->eStartAngle, 
888                  lpAngleArc->eSweepAngle );
889
890         break;
891       }
892  
893     case EMR_ROUNDRECT: 
894       {
895         PEMRROUNDRECT lpRoundRect = (PEMRROUNDRECT)mr;
896
897         RoundRect( hdc, 
898                    lpRoundRect->rclBox.left,
899                    lpRoundRect->rclBox.top,
900                    lpRoundRect->rclBox.right,
901                    lpRoundRect->rclBox.bottom,
902                    lpRoundRect->szlCorner.cx,
903                    lpRoundRect->szlCorner.cy );
904
905         break; 
906       }
907
908     case EMR_ARC:
909       {
910         PEMRARC lpArc = (PEMRARC)mr;
911
912         Arc( hdc,  
913              (INT)lpArc->rclBox.left,
914              (INT)lpArc->rclBox.top,
915              (INT)lpArc->rclBox.right,
916              (INT)lpArc->rclBox.bottom,
917              (INT)lpArc->ptlStart.x, 
918              (INT)lpArc->ptlStart.y,
919              (INT)lpArc->ptlEnd.x,
920              (INT)lpArc->ptlEnd.y );
921
922         break;  
923       }
924
925     case EMR_CHORD:
926       {
927         PEMRCHORD lpChord = (PEMRCHORD)mr;
928
929         Chord( hdc,
930              (INT)lpChord->rclBox.left,
931              (INT)lpChord->rclBox.top,
932              (INT)lpChord->rclBox.right,
933              (INT)lpChord->rclBox.bottom,
934              (INT)lpChord->ptlStart.x,
935              (INT)lpChord->ptlStart.y,
936              (INT)lpChord->ptlEnd.x,
937              (INT)lpChord->ptlEnd.y );
938
939         break;
940       }
941
942     case EMR_PIE:
943       {
944         PEMRPIE lpPie = (PEMRPIE)mr;
945
946         Pie( hdc,
947              (INT)lpPie->rclBox.left,
948              (INT)lpPie->rclBox.top,
949              (INT)lpPie->rclBox.right,
950              (INT)lpPie->rclBox.bottom,
951              (INT)lpPie->ptlStart.x,
952              (INT)lpPie->ptlStart.y,
953              (INT)lpPie->ptlEnd.x,
954              (INT)lpPie->ptlEnd.y );
955
956        break;
957       }
958
959     case EMR_ARCTO: 
960       {
961         PEMRARC lpArcTo = (PEMRARC)mr;
962
963         ArcTo( hdc,
964                (INT)lpArcTo->rclBox.left,
965                (INT)lpArcTo->rclBox.top,
966                (INT)lpArcTo->rclBox.right,
967                (INT)lpArcTo->rclBox.bottom,
968                (INT)lpArcTo->ptlStart.x,
969                (INT)lpArcTo->ptlStart.y,
970                (INT)lpArcTo->ptlEnd.x,
971                (INT)lpArcTo->ptlEnd.y );
972
973         break;
974       }
975
976     case EMR_EXTFLOODFILL:
977       {
978         PEMREXTFLOODFILL lpExtFloodFill = (PEMREXTFLOODFILL)mr;
979
980         ExtFloodFill( hdc, 
981                       (INT)lpExtFloodFill->ptlStart.x,
982                       (INT)lpExtFloodFill->ptlStart.y,
983                       lpExtFloodFill->crColor,
984                       (UINT)lpExtFloodFill->iMode );
985
986         break;
987       }
988
989     case EMR_POLYDRAW:
990       {
991         PEMRPOLYDRAW lpPolyDraw = (PEMRPOLYDRAW)mr;
992         PolyDraw( hdc, 
993                   (const LPPOINT)lpPolyDraw->aptl,
994                   lpPolyDraw->abTypes,
995                   (INT)lpPolyDraw->cptl );
996  
997         break;
998       } 
999
1000     case EMR_SETARCDIRECTION:
1001       {
1002         PEMRSETARCDIRECTION lpSetArcDirection = (PEMRSETARCDIRECTION)mr;
1003         SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection );
1004         break;
1005       }
1006
1007     case EMR_SETMITERLIMIT:
1008       {
1009         PEMRSETMITERLIMIT lpSetMiterLimit = (PEMRSETMITERLIMIT)mr;
1010         SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL );
1011         break;
1012       } 
1013
1014     case EMR_BEGINPATH:
1015       {
1016         BeginPath( hdc );
1017         break;
1018       }
1019
1020     case EMR_ENDPATH: 
1021       {
1022         EndPath( hdc );
1023         break;
1024       }
1025
1026     case EMR_CLOSEFIGURE:
1027       {
1028         CloseFigure( hdc );
1029         break;
1030       }
1031
1032     case EMR_FILLPATH:
1033       {
1034         /*PEMRFILLPATH lpFillPath = (PEMRFILLPATH)mr;*/
1035         FillPath( hdc );
1036         break;
1037       }
1038
1039     case EMR_STROKEANDFILLPATH:
1040       {
1041         /*PEMRSTROKEANDFILLPATH lpStrokeAndFillPath = (PEMRSTROKEANDFILLPATH)mr;*/
1042         StrokeAndFillPath( hdc );
1043         break;
1044       }
1045
1046     case EMR_STROKEPATH:
1047       {
1048         /*PEMRSTROKEPATH lpStrokePath = (PEMRSTROKEPATH)mr;*/
1049         StrokePath( hdc );
1050         break;
1051       }
1052
1053     case EMR_FLATTENPATH:
1054       {
1055         FlattenPath( hdc ); 
1056         break;
1057       }
1058
1059     case EMR_WIDENPATH:
1060       {
1061         WidenPath( hdc );
1062         break;
1063       }
1064
1065     case EMR_SELECTCLIPPATH:
1066       {
1067         PEMRSELECTCLIPPATH lpSelectClipPath = (PEMRSELECTCLIPPATH)mr;
1068         SelectClipPath( hdc, (INT)lpSelectClipPath->iMode );
1069         break;
1070       }
1071  
1072     case EMR_ABORTPATH:
1073       {
1074         AbortPath( hdc );
1075         break;
1076       }
1077
1078     case EMR_CREATECOLORSPACE:
1079       {
1080         PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr;
1081         (handletable->objectHandle)[lpCreateColorSpace->ihCS] = 
1082            CreateColorSpaceA( &lpCreateColorSpace->lcs ); 
1083         break;
1084       }
1085
1086     case EMR_SETCOLORSPACE:
1087       {
1088         PEMRSETCOLORSPACE lpSetColorSpace = (PEMRSETCOLORSPACE)mr; 
1089         SetColorSpace( hdc, 
1090                        (handletable->objectHandle)[lpSetColorSpace->ihCS] );
1091         break;
1092       }
1093
1094     case EMR_DELETECOLORSPACE:
1095       {
1096         PEMRDELETECOLORSPACE lpDeleteColorSpace = (PEMRDELETECOLORSPACE)mr;
1097         DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] );
1098         break; 
1099       }
1100
1101     case EMR_SETICMMODE:
1102       {
1103         PERMSETICMMODE lpSetICMMode = (PERMSETICMMODE)mr;
1104         SetICMMode( hdc, (INT)lpSetICMMode->iMode );
1105         break;
1106       }
1107
1108     case EMR_PIXELFORMAT: 
1109       {
1110         INT iPixelFormat;
1111         PEMRPIXELFORMAT lpPixelFormat = (PEMRPIXELFORMAT)mr;
1112
1113         iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd );
1114         SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd ); 
1115          
1116         break;
1117       }
1118
1119     case EMR_SETPALETTEENTRIES:  
1120       {
1121         PEMRSETPALETTEENTRIES lpSetPaletteEntries = (PEMRSETPALETTEENTRIES)mr;
1122
1123         SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal],
1124                            (UINT)lpSetPaletteEntries->iStart,
1125                            (UINT)lpSetPaletteEntries->cEntries,
1126                            lpSetPaletteEntries->aPalEntries ); 
1127                            
1128         break;
1129       }
1130
1131     case EMR_RESIZEPALETTE:
1132       {
1133         PEMRRESIZEPALETTE lpResizePalette = (PEMRRESIZEPALETTE)mr;
1134
1135         ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal],
1136                        (UINT)lpResizePalette->cEntries );
1137
1138         break;
1139       }
1140
1141     case EMR_CREATEDIBPATTERNBRUSHPT:
1142       {
1143         PEMRCREATEDIBPATTERNBRUSHPT lpCreate = (PEMRCREATEDIBPATTERNBRUSHPT)mr;
1144
1145         /* This is a BITMAPINFO struct followed directly by bitmap bits */
1146         LPVOID lpPackedStruct = HeapAlloc( GetProcessHeap(), 
1147                                            0, 
1148                                            lpCreate->cbBmi + lpCreate->cbBits );
1149         /* Now pack this structure */
1150         memcpy( lpPackedStruct, 
1151                 ((BYTE*)lpCreate) + lpCreate->offBmi,
1152                 lpCreate->cbBmi ); 
1153         memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi,
1154                 ((BYTE*)lpCreate) + lpCreate->offBits,
1155                 lpCreate->cbBits );
1156
1157         (handletable->objectHandle)[lpCreate->ihBrush] = 
1158            CreateDIBPatternBrushPt( lpPackedStruct,
1159                                     (UINT)lpCreate->iUsage ); 
1160
1161         break; 
1162       }
1163
1164     case EMR_CREATEMONOBRUSH:
1165     {
1166         PEMRCREATEMONOBRUSH pCreateMonoBrush = (PEMRCREATEMONOBRUSH)mr;
1167         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pCreateMonoBrush->offBmi);
1168         HBITMAP hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1169                 (BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1170         (handletable->objectHandle)[pCreateMonoBrush->ihBrush] = CreatePatternBrush(hBmp);
1171         /* CreatePatternBrush created a copy of the bitmap */
1172         DeleteObject(hBmp);
1173         break;
1174     }
1175
1176     case EMR_BITBLT:
1177     {
1178         PEMRBITBLT pBitBlt = (PEMRBITBLT)mr;
1179         HDC hdcSrc = CreateCompatibleDC(hdc);
1180         HBRUSH hBrush, hBrushOld;
1181         HBITMAP hBmp, hBmpOld;
1182         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pBitBlt->offBmiSrc);
1183
1184         SetWorldTransform(hdcSrc, &pBitBlt->xformSrc);
1185
1186         hBrush = CreateSolidBrush(pBitBlt->crBkColorSrc);
1187         hBrushOld = SelectObject(hdcSrc, hBrush);
1188         PatBlt(hdcSrc, pBitBlt->rclBounds.left, pBitBlt->rclBounds.top,
1189                pBitBlt->rclBounds.right - pBitBlt->rclBounds.left,
1190                pBitBlt->rclBounds.bottom - pBitBlt->rclBounds.top, PATCOPY);
1191         SelectObject(hdcSrc, hBrushOld);
1192         DeleteObject(hBrush);
1193
1194         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1195                               (BYTE *)mr + pBitBlt->offBitsSrc, pbi, pBitBlt->iUsageSrc);
1196         hBmpOld = SelectObject(hdcSrc, hBmp);
1197         BitBlt(hdc,
1198                pBitBlt->xDest,
1199                pBitBlt->yDest,
1200                pBitBlt->cxDest,
1201                pBitBlt->cyDest,
1202                hdcSrc,
1203                pBitBlt->xSrc,
1204                pBitBlt->ySrc,
1205                pBitBlt->dwRop);
1206         SelectObject(hdcSrc, hBmpOld);
1207         DeleteObject(hBmp);
1208         DeleteDC(hdcSrc);
1209         break;
1210     }
1211
1212     case EMR_STRETCHBLT:
1213     {
1214         PEMRSTRETCHBLT pStretchBlt= (PEMRSTRETCHBLT)mr;
1215         HDC hdcSrc = CreateCompatibleDC(hdc);
1216         HBRUSH hBrush, hBrushOld;
1217         HBITMAP hBmp, hBmpOld;
1218         BITMAPINFO *pbi = (BITMAPINFO *)((BYTE *)mr + pStretchBlt->offBmiSrc);
1219
1220         SetWorldTransform(hdcSrc, &pStretchBlt->xformSrc);
1221
1222         hBrush = CreateSolidBrush(pStretchBlt->crBkColorSrc);
1223         hBrushOld = SelectObject(hdcSrc, hBrush);
1224         PatBlt(hdcSrc, pStretchBlt->rclBounds.left, pStretchBlt->rclBounds.top,
1225                pStretchBlt->rclBounds.right - pStretchBlt->rclBounds.left,
1226                pStretchBlt->rclBounds.bottom - pStretchBlt->rclBounds.top, PATCOPY);
1227         SelectObject(hdcSrc, hBrushOld);
1228         DeleteObject(hBrush);
1229
1230         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1231                               (BYTE *)mr + pStretchBlt->offBitsSrc, pbi, pStretchBlt->iUsageSrc);
1232         hBmpOld = SelectObject(hdcSrc, hBmp);
1233         StretchBlt(hdc,
1234                pStretchBlt->xDest,
1235                pStretchBlt->yDest,
1236                pStretchBlt->cxDest,
1237                pStretchBlt->cyDest,
1238                hdcSrc,
1239                pStretchBlt->xSrc,
1240                pStretchBlt->ySrc,
1241                pStretchBlt->cxSrc,
1242                pStretchBlt->cySrc,
1243                pStretchBlt->dwRop);
1244         SelectObject(hdcSrc, hBmpOld);
1245         DeleteObject(hBmp);
1246         DeleteDC(hdcSrc);
1247         break;
1248     }
1249
1250     case EMR_MASKBLT:
1251     {
1252         PEMRMASKBLT pMaskBlt= (PEMRMASKBLT)mr;
1253         HDC hdcSrc = CreateCompatibleDC(hdc);
1254         HBRUSH hBrush, hBrushOld;
1255         HBITMAP hBmp, hBmpOld, hBmpMask;
1256         BITMAPINFO *pbi;
1257
1258         SetWorldTransform(hdcSrc, &pMaskBlt->xformSrc);
1259
1260         hBrush = CreateSolidBrush(pMaskBlt->crBkColorSrc);
1261         hBrushOld = SelectObject(hdcSrc, hBrush);
1262         PatBlt(hdcSrc, pMaskBlt->rclBounds.left, pMaskBlt->rclBounds.top,
1263                pMaskBlt->rclBounds.right - pMaskBlt->rclBounds.left,
1264                pMaskBlt->rclBounds.bottom - pMaskBlt->rclBounds.top, PATCOPY);
1265         SelectObject(hdcSrc, hBrushOld);
1266         DeleteObject(hBrush);
1267
1268         pbi = (BITMAPINFO *)((BYTE *)mr + pMaskBlt->offBmiMask);
1269         hBmpMask = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1270                               (BYTE *)mr + pMaskBlt->offBitsMask, pbi, pMaskBlt->iUsageMask);
1271
1272         pbi = (BITMAPINFO *)((BYTE *)mr + pMaskBlt->offBmiSrc);
1273         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1274                               (BYTE *)mr + pMaskBlt->offBitsSrc, pbi, pMaskBlt->iUsageSrc);
1275         hBmpOld = SelectObject(hdcSrc, hBmp);
1276         MaskBlt(hdc,
1277                 pMaskBlt->xDest,
1278                 pMaskBlt->yDest,
1279                 pMaskBlt->cxDest,
1280                 pMaskBlt->cyDest,
1281                 hdcSrc,
1282                 pMaskBlt->xSrc,
1283                 pMaskBlt->ySrc,
1284                 hBmpMask,
1285                 pMaskBlt->xMask,
1286                 pMaskBlt->yMask,
1287                 pMaskBlt->dwRop);
1288         SelectObject(hdcSrc, hBmpOld);
1289         DeleteObject(hBmp);
1290         DeleteObject(hBmpMask);
1291         DeleteDC(hdcSrc);
1292         break;
1293     }
1294
1295     case EMR_PLGBLT:
1296     {
1297         PEMRPLGBLT pPlgBlt= (PEMRPLGBLT)mr;
1298         HDC hdcSrc = CreateCompatibleDC(hdc);
1299         HBRUSH hBrush, hBrushOld;
1300         HBITMAP hBmp, hBmpOld, hBmpMask;
1301         BITMAPINFO *pbi;
1302         POINT pts[3];
1303
1304         SetWorldTransform(hdcSrc, &pPlgBlt->xformSrc);
1305
1306         pts[0].x = pPlgBlt->aptlDst[0].x; pts[0].y = pPlgBlt->aptlDst[0].y;
1307         pts[1].x = pPlgBlt->aptlDst[1].x; pts[1].y = pPlgBlt->aptlDst[1].y;
1308         pts[2].x = pPlgBlt->aptlDst[2].x; pts[2].y = pPlgBlt->aptlDst[2].y;
1309
1310         hBrush = CreateSolidBrush(pPlgBlt->crBkColorSrc);
1311         hBrushOld = SelectObject(hdcSrc, hBrush);
1312         PatBlt(hdcSrc, pPlgBlt->rclBounds.left, pPlgBlt->rclBounds.top,
1313                pPlgBlt->rclBounds.right - pPlgBlt->rclBounds.left,
1314                pPlgBlt->rclBounds.bottom - pPlgBlt->rclBounds.top, PATCOPY);
1315         SelectObject(hdcSrc, hBrushOld);
1316         DeleteObject(hBrush);
1317
1318         pbi = (BITMAPINFO *)((BYTE *)mr + pPlgBlt->offBmiMask);
1319         hBmpMask = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1320                               (BYTE *)mr + pPlgBlt->offBitsMask, pbi, pPlgBlt->iUsageMask);
1321
1322         pbi = (BITMAPINFO *)((BYTE *)mr + pPlgBlt->offBmiSrc);
1323         hBmp = CreateDIBitmap(0, (BITMAPINFOHEADER *)pbi, CBM_INIT,
1324                               (BYTE *)mr + pPlgBlt->offBitsSrc, pbi, pPlgBlt->iUsageSrc);
1325         hBmpOld = SelectObject(hdcSrc, hBmp);
1326         PlgBlt(hdc,
1327                pts,
1328                hdcSrc,
1329                pPlgBlt->xSrc,
1330                pPlgBlt->ySrc,
1331                pPlgBlt->cxSrc,
1332                pPlgBlt->cySrc,
1333                hBmpMask,
1334                pPlgBlt->xMask,
1335                pPlgBlt->yMask);
1336         SelectObject(hdcSrc, hBmpOld);
1337         DeleteObject(hBmp);
1338         DeleteObject(hBmpMask);
1339         DeleteDC(hdcSrc);
1340         break;
1341     }
1342
1343     case EMR_SETDIBITSTODEVICE:
1344     {
1345         PEMRSETDIBITSTODEVICE pSetDIBitsToDevice = (PEMRSETDIBITSTODEVICE)mr;
1346
1347         SetDIBitsToDevice(hdc,
1348                           pSetDIBitsToDevice->xDest,
1349                           pSetDIBitsToDevice->yDest,
1350                           pSetDIBitsToDevice->cxSrc,
1351                           pSetDIBitsToDevice->cySrc,
1352                           pSetDIBitsToDevice->xSrc,
1353                           pSetDIBitsToDevice->ySrc,
1354                           pSetDIBitsToDevice->iStartScan,
1355                           pSetDIBitsToDevice->cScans,
1356                           (BYTE *)mr + pSetDIBitsToDevice->offBitsSrc,
1357                           (BITMAPINFO *)((BYTE *)mr + pSetDIBitsToDevice->offBmiSrc),
1358                           pSetDIBitsToDevice->iUsageSrc);
1359         break;
1360     }
1361
1362     case EMR_POLYTEXTOUTA:
1363     {
1364         PEMRPOLYTEXTOUTA pPolyTextOutA = (PEMRPOLYTEXTOUTA)mr;
1365         POLYTEXTA *polytextA = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutA->cStrings * sizeof(POLYTEXTA));
1366         LONG i;
1367         XFORM xform, xformOld;
1368         int gModeOld;
1369
1370         gModeOld = SetGraphicsMode(hdc, pPolyTextOutA->iGraphicsMode);
1371         GetWorldTransform(hdc, &xformOld);
1372
1373         xform.eM11 = pPolyTextOutA->exScale;
1374         xform.eM12 = 0.0;
1375         xform.eM21 = 0.0;
1376         xform.eM22 = pPolyTextOutA->eyScale;
1377         xform.eDx = 0.0;
1378         xform.eDy = 0.0;
1379         SetWorldTransform(hdc, &xform);
1380
1381         /* Set up POLYTEXTA structures */
1382         for(i = 0; i < pPolyTextOutA->cStrings; i++)
1383         {
1384             polytextA[i].x = pPolyTextOutA->aemrtext[i].ptlReference.x;
1385             polytextA[i].y = pPolyTextOutA->aemrtext[i].ptlReference.y;
1386             polytextA[i].n = pPolyTextOutA->aemrtext[i].nChars;
1387             polytextA[i].lpstr = (LPSTR)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offString);
1388             polytextA[i].uiFlags = pPolyTextOutA->aemrtext[i].fOptions;
1389             polytextA[i].rcl.left = pPolyTextOutA->aemrtext[i].rcl.left;
1390             polytextA[i].rcl.right = pPolyTextOutA->aemrtext[i].rcl.right;
1391             polytextA[i].rcl.top = pPolyTextOutA->aemrtext[i].rcl.top;
1392             polytextA[i].rcl.bottom = pPolyTextOutA->aemrtext[i].rcl.bottom;
1393             polytextA[i].pdx = (int *)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offDx);
1394         }
1395         PolyTextOutA(hdc, polytextA, pPolyTextOutA->cStrings);
1396         HeapFree(GetProcessHeap(), 0, polytextA);
1397
1398         SetWorldTransform(hdc, &xformOld);
1399         SetGraphicsMode(hdc, gModeOld);
1400         break;
1401     }
1402
1403     case EMR_POLYTEXTOUTW:
1404     {
1405         PEMRPOLYTEXTOUTW pPolyTextOutW = (PEMRPOLYTEXTOUTW)mr;
1406         POLYTEXTW *polytextW = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutW->cStrings * sizeof(POLYTEXTW));
1407         LONG i;
1408         XFORM xform, xformOld;
1409         int gModeOld;
1410
1411         gModeOld = SetGraphicsMode(hdc, pPolyTextOutW->iGraphicsMode);
1412         GetWorldTransform(hdc, &xformOld);
1413
1414         xform.eM11 = pPolyTextOutW->exScale;
1415         xform.eM12 = 0.0;
1416         xform.eM21 = 0.0;
1417         xform.eM22 = pPolyTextOutW->eyScale;
1418         xform.eDx = 0.0;
1419         xform.eDy = 0.0;
1420         SetWorldTransform(hdc, &xform);
1421
1422         /* Set up POLYTEXTW structures */
1423         for(i = 0; i < pPolyTextOutW->cStrings; i++)
1424         {
1425             polytextW[i].x = pPolyTextOutW->aemrtext[i].ptlReference.x;
1426             polytextW[i].y = pPolyTextOutW->aemrtext[i].ptlReference.y;
1427             polytextW[i].n = pPolyTextOutW->aemrtext[i].nChars;
1428             polytextW[i].lpstr = (LPWSTR)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offString);
1429             polytextW[i].uiFlags = pPolyTextOutW->aemrtext[i].fOptions;
1430             polytextW[i].rcl.left = pPolyTextOutW->aemrtext[i].rcl.left;
1431             polytextW[i].rcl.right = pPolyTextOutW->aemrtext[i].rcl.right;
1432             polytextW[i].rcl.top = pPolyTextOutW->aemrtext[i].rcl.top;
1433             polytextW[i].rcl.bottom = pPolyTextOutW->aemrtext[i].rcl.bottom;
1434             polytextW[i].pdx = (int *)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offDx);
1435         }
1436         PolyTextOutW(hdc, polytextW, pPolyTextOutW->cStrings);
1437         HeapFree(GetProcessHeap(), 0, polytextW);
1438
1439         SetWorldTransform(hdc, &xformOld);
1440         SetGraphicsMode(hdc, gModeOld);
1441         break;
1442     }
1443
1444     case EMR_FILLRGN:
1445     {
1446         PEMRFILLRGN pFillRgn = (PEMRFILLRGN)mr;
1447         HRGN hRgn = ExtCreateRegion(NULL, pFillRgn->cbRgnData, (RGNDATA *)pFillRgn->RgnData);
1448         FillRgn(hdc,
1449                 hRgn,
1450                 (handletable->objectHandle)[pFillRgn->ihBrush]);
1451         DeleteObject(hRgn);
1452         break;
1453     }
1454
1455     case EMR_FRAMERGN:
1456     {
1457         PEMRFRAMERGN pFrameRgn = (PEMRFRAMERGN)mr;
1458         HRGN hRgn = ExtCreateRegion(NULL, pFrameRgn->cbRgnData, (RGNDATA *)pFrameRgn->RgnData);
1459         FrameRgn(hdc,
1460                  hRgn,
1461                  (handletable->objectHandle)[pFrameRgn->ihBrush],
1462                  pFrameRgn->szlStroke.cx,
1463                  pFrameRgn->szlStroke.cy);
1464         DeleteObject(hRgn);
1465         break;
1466     }
1467
1468     case EMR_INVERTRGN:
1469     {
1470         PEMRINVERTRGN pInvertRgn = (PEMRINVERTRGN)mr;
1471         HRGN hRgn = ExtCreateRegion(NULL, pInvertRgn->cbRgnData, (RGNDATA *)pInvertRgn->RgnData);
1472         InvertRgn(hdc, hRgn);
1473         DeleteObject(hRgn);
1474         break;
1475     }
1476
1477     case EMR_PAINTRGN:
1478     {
1479         PEMRPAINTRGN pPaintRgn = (PEMRPAINTRGN)mr;
1480         HRGN hRgn = ExtCreateRegion(NULL, pPaintRgn->cbRgnData, (RGNDATA *)pPaintRgn->RgnData);
1481         PaintRgn(hdc, hRgn);
1482         DeleteObject(hRgn);
1483         break;
1484     }
1485
1486     case EMR_POLYDRAW16:
1487     case EMR_GLSRECORD:
1488     case EMR_GLSBOUNDEDRECORD:
1489     default:
1490       /* From docs: If PlayEnhMetaFileRecord doesn't recognize a 
1491                     record then ignore and return TRUE. */
1492       FIXME("type %d is unimplemented\n", type);
1493       break;
1494     }
1495   return TRUE;
1496 }
1497
1498
1499 /*****************************************************************************
1500  *
1501  *        EnumEnhMetaFile  (GDI32.@)
1502  *
1503  *  Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
1504  *  for each
1505  *  record. Returns when either every record has been used or 
1506  *  when _EnhMetaFunc_ returns FALSE.
1507  *
1508  *
1509  * RETURNS
1510  *  TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
1511  *  returns FALSE.
1512  *
1513  * BUGS
1514  *   Ignores rect.
1515  */
1516 BOOL WINAPI EnumEnhMetaFile( 
1517      HDC hdc,                /* [in] device context to pass to _EnhMetaFunc_ */
1518      HENHMETAFILE hmf,       /* [in] EMF to walk */
1519      ENHMFENUMPROC callback, /* [in] callback function */ 
1520      LPVOID data,            /* [in] optional data for callback function */
1521      const RECT *lpRect      /* [in] bounding rectangle for rendered metafile */
1522     )
1523 {
1524     BOOL ret;
1525     ENHMETAHEADER *emh;
1526     ENHMETARECORD *emr;
1527     DWORD offset;
1528     UINT i;
1529     HANDLETABLE *ht;
1530     INT savedMode = 0;
1531     FLOAT xSrcPixSize, ySrcPixSize, xscale, yscale;
1532     XFORM savedXform, xform;
1533     HPEN hPen = (HPEN)NULL;
1534     HBRUSH hBrush = (HBRUSH)NULL;
1535     HFONT hFont = (HFONT)NULL;
1536
1537     if(!lpRect)
1538     {
1539         SetLastError(ERROR_INVALID_PARAMETER);
1540         return FALSE;
1541     }
1542
1543     emh = EMF_GetEnhMetaHeader(hmf);
1544     if(!emh) {
1545         SetLastError(ERROR_INVALID_HANDLE);
1546         return FALSE;
1547     }
1548
1549     ht = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1550                     sizeof(HANDLETABLE) * emh->nHandles );
1551     if(!ht)
1552     {
1553         SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1554         return FALSE;
1555     }
1556     ht->objectHandle[0] = hmf;
1557
1558     if (hdc)
1559     {
1560         TRACE("rect: %d,%d - %d,%d. rclFrame: %ld,%ld - %ld,%ld\n",
1561               lpRect->left, lpRect->top, lpRect->right, lpRect->bottom,
1562               emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
1563               emh->rclFrame.bottom);
1564
1565         xSrcPixSize = (FLOAT) emh->szlMillimeters.cx / emh->szlDevice.cx;
1566         ySrcPixSize = (FLOAT) emh->szlMillimeters.cy / emh->szlDevice.cy;
1567         xscale = (FLOAT)(lpRect->right - lpRect->left) * 100.0 /
1568           (emh->rclFrame.right - emh->rclFrame.left) * xSrcPixSize;
1569         yscale = (FLOAT)(lpRect->bottom - lpRect->top) * 100.0 /
1570           (emh->rclFrame.bottom - emh->rclFrame.top) * ySrcPixSize;
1571
1572         xform.eM11 = xscale;
1573         xform.eM12 = 0;
1574         xform.eM21 = 0;
1575         xform.eM22 = yscale;
1576         xform.eDx = (FLOAT) lpRect->left - (lpRect->right - lpRect->left) *
1577           emh->rclFrame.left / (emh->rclFrame.right - emh->rclFrame.left);
1578         xform.eDy = (FLOAT) lpRect->top - (lpRect->bottom - lpRect->top) *
1579           emh->rclFrame.top / (emh->rclFrame.bottom - emh->rclFrame.top);
1580
1581         savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
1582         GetWorldTransform(hdc, &savedXform);
1583
1584         if (!ModifyWorldTransform(hdc, &xform, MWT_RIGHTMULTIPLY)) {
1585             ERR("World transform failed!\n");
1586         }
1587
1588         /* save the current pen, brush and font */
1589         hPen = GetCurrentObject(hdc, OBJ_PEN);
1590         hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
1591         hFont = GetCurrentObject(hdc, OBJ_FONT);
1592     }
1593
1594     TRACE("nSize = %ld, nBytes = %ld, nHandles = %d, nRecords = %ld, nPalEntries = %ld\n",
1595         emh->nSize, emh->nBytes, emh->nHandles, emh->nRecords, emh->nPalEntries);
1596
1597     ret = TRUE;
1598     offset = 0;
1599     while(ret && offset < emh->nBytes)
1600     {
1601         emr = (ENHMETARECORD *)((char *)emh + offset);
1602         TRACE("Calling EnumFunc with record type %ld, size %ld\n", emr->iType, emr->nSize);
1603         ret = (*callback)(hdc, ht, emr, emh->nHandles, data);
1604         offset += emr->nSize;
1605     }
1606
1607     if (hdc)
1608     {
1609         /* restore pen, brush and font */
1610         SelectObject(hdc, hBrush);
1611         SelectObject(hdc, hPen);
1612         SelectObject(hdc, hFont);
1613
1614         SetWorldTransform(hdc, &savedXform);
1615         if (savedMode)
1616             SetGraphicsMode(hdc, savedMode);
1617     }
1618
1619     for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */
1620         if( (ht->objectHandle)[i] )
1621             DeleteObject( (ht->objectHandle)[i] );
1622
1623     HeapFree( GetProcessHeap(), 0, ht );
1624     return ret;
1625 }
1626
1627 static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht,
1628                                                 ENHMETARECORD *emr,
1629                                                 INT handles, LPVOID data)
1630 {
1631     return PlayEnhMetaFileRecord(hdc, ht, emr, handles);
1632 }
1633                                                 
1634 /**************************************************************************
1635  *    PlayEnhMetaFile  (GDI32.@)
1636  *
1637  *    Renders an enhanced metafile into a specified rectangle *lpRect
1638  *    in device context hdc.
1639  *
1640  */
1641 BOOL WINAPI PlayEnhMetaFile( 
1642        HDC hdc,           /* [in] DC to render into */
1643        HENHMETAFILE hmf,  /* [in] metafile to render */
1644        const RECT *lpRect /* [in] rectangle to place metafile inside */
1645       )
1646 {
1647     return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL,
1648                            lpRect);
1649 }
1650
1651 /*****************************************************************************
1652  *  DeleteEnhMetaFile (GDI32.@)
1653  *
1654  *  Deletes an enhanced metafile and frees the associated storage.
1655  */
1656 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
1657 {
1658     return EMF_Delete_HENHMETAFILE( hmf );
1659 }
1660
1661 /*****************************************************************************
1662  *  CopyEnhMetaFileA (GDI32.@)  Duplicate an enhanced metafile
1663  *
1664  *   
1665  */
1666 HENHMETAFILE WINAPI CopyEnhMetaFileA(
1667     HENHMETAFILE hmfSrc, 
1668     LPCSTR file)
1669 {
1670     ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
1671     HENHMETAFILE hmfDst;
1672
1673     if(!emrSrc) return FALSE;
1674     if (!file) {
1675         emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
1676         memcpy( emrDst, emrSrc, emrSrc->nBytes );
1677         hmfDst = EMF_Create_HENHMETAFILE( emrDst, FALSE );
1678     } else {
1679         HANDLE hFile;
1680         hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0, NULL,
1681                              CREATE_ALWAYS, 0, 0);
1682         WriteFile( hFile, emrSrc, emrSrc->nBytes, 0, 0);
1683         hmfDst = EMF_GetEnhMetaFile( hFile );
1684         CloseHandle( hFile );
1685     }
1686     return hmfDst;
1687 }
1688
1689
1690 /* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */
1691 typedef struct tagEMF_PaletteCopy
1692 {
1693    UINT cEntries;
1694    LPPALETTEENTRY lpPe;
1695 } EMF_PaletteCopy;
1696
1697 /***************************************************************  
1698  * Find the EMR_EOF record and then use it to find the
1699  * palette entries for this enhanced metafile. 
1700  * The lpData is actually a pointer to a EMF_PaletteCopy struct  
1701  * which contains the max number of elements to copy and where
1702  * to copy them to.
1703  *
1704  * NOTE: To be used by GetEnhMetaFilePaletteEntries only!
1705  */
1706 INT CALLBACK cbEnhPaletteCopy( HDC a,
1707                                LPHANDLETABLE b,
1708                                LPENHMETARECORD lpEMR,
1709                                INT c,
1710                                LPVOID lpData )
1711 {
1712  
1713   if ( lpEMR->iType == EMR_EOF )
1714   {
1715     PEMREOF lpEof = (PEMREOF)lpEMR;
1716     EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData;
1717     DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries );
1718
1719     TRACE( "copying 0x%08lx palettes\n", dwNumPalToCopy );
1720
1721     memcpy( (LPVOID)info->lpPe, 
1722             (LPVOID)(((LPSTR)lpEof) + lpEof->offPalEntries), 
1723             sizeof( *(info->lpPe) ) * dwNumPalToCopy );
1724
1725     /* Update the passed data as a return code */
1726     info->lpPe     = NULL; /* Palettes were copied! */
1727     info->cEntries = (UINT)dwNumPalToCopy;  
1728
1729     return FALSE; /* That's all we need */
1730   }
1731   
1732   return TRUE;
1733 }
1734
1735 /*****************************************************************************
1736  *  GetEnhMetaFilePaletteEntries (GDI32.@)  
1737  * 
1738  *  Copy the palette and report size  
1739  * 
1740  *  BUGS: Error codes (SetLastError) are not set on failures
1741  */
1742 UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
1743                                           UINT cEntries,
1744                                           LPPALETTEENTRY lpPe )
1745 {
1746   ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf );
1747   EMF_PaletteCopy infoForCallBack; 
1748
1749   TRACE( "(%04x,%d,%p)\n", hEmf, cEntries, lpPe ); 
1750
1751   /* First check if there are any palettes associated with
1752      this metafile. */
1753   if ( enhHeader->nPalEntries == 0 ) return 0;
1754
1755   /* Is the user requesting the number of palettes? */
1756   if ( lpPe == NULL ) return (UINT)enhHeader->nPalEntries;
1757
1758   /* Copy cEntries worth of PALETTEENTRY structs into the buffer */
1759   infoForCallBack.cEntries = cEntries;
1760   infoForCallBack.lpPe     = lpPe; 
1761
1762   if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy, 
1763                          &infoForCallBack, NULL ) )
1764       return GDI_ERROR;
1765
1766   /* Verify that the callback executed correctly */
1767   if ( infoForCallBack.lpPe != NULL )
1768   {
1769      /* Callback proc had error! */
1770      ERR( "cbEnhPaletteCopy didn't execute correctly\n" );
1771      return GDI_ERROR;
1772   }
1773
1774   return infoForCallBack.cEntries;
1775 }
1776
1777 /******************************************************************
1778  *         SetWinMetaFileBits   (GDI32.@)
1779  *      
1780  *         Translate from old style to new style.
1781  *
1782  * BUGS: - This doesn't take the DC and scaling into account
1783  *       - Most record conversions aren't implemented
1784  *       - Handle slot assignement is primative and most likely doesn't work
1785  */
1786 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer,
1787                                            CONST BYTE *lpbBuffer,
1788                                            HDC hdcRef,
1789                                            CONST METAFILEPICT *lpmfp
1790                                            ) 
1791 {
1792      HENHMETAFILE    hMf;
1793      LPVOID          lpNewEnhMetaFileBuffer = NULL;
1794      UINT            uNewEnhMetaFileBufferSize = 0;
1795      BOOL            bFoundEOF = FALSE;
1796
1797      FIXME( "(%d,%p,%04x,%p):stub\n", cbBuffer, lpbBuffer, hdcRef, lpmfp );
1798
1799      /* 1. Get the header - skip over this and get straight to the records  */
1800
1801      uNewEnhMetaFileBufferSize = sizeof( ENHMETAHEADER );
1802      lpNewEnhMetaFileBuffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, 
1803                                          uNewEnhMetaFileBufferSize );
1804
1805      if( lpNewEnhMetaFileBuffer == NULL )
1806      {
1807        goto error; 
1808      }
1809
1810      /* Fill in the header record */ 
1811      {
1812        LPENHMETAHEADER lpNewEnhMetaFileHeader = (LPENHMETAHEADER)lpNewEnhMetaFileBuffer;
1813
1814        lpNewEnhMetaFileHeader->iType = EMR_HEADER;
1815        lpNewEnhMetaFileHeader->nSize = sizeof( ENHMETAHEADER );
1816
1817        /* FIXME: Not right. Must be able to get this from the DC */
1818        lpNewEnhMetaFileHeader->rclBounds.left   = 0;
1819        lpNewEnhMetaFileHeader->rclBounds.right  = 0;
1820        lpNewEnhMetaFileHeader->rclBounds.top    = 0;
1821        lpNewEnhMetaFileHeader->rclBounds.bottom = 0;
1822
1823        /* FIXME: Not right. Must be able to get this from the DC */
1824        lpNewEnhMetaFileHeader->rclFrame.left   = 0;
1825        lpNewEnhMetaFileHeader->rclFrame.right  = 0;
1826        lpNewEnhMetaFileHeader->rclFrame.top    = 0;
1827        lpNewEnhMetaFileHeader->rclFrame.bottom = 0;
1828
1829        lpNewEnhMetaFileHeader->dSignature=ENHMETA_SIGNATURE;
1830        lpNewEnhMetaFileHeader->nVersion=0x10000;
1831        lpNewEnhMetaFileHeader->nBytes = lpNewEnhMetaFileHeader->nSize;
1832        lpNewEnhMetaFileHeader->sReserved=0;
1833
1834         /* FIXME: if there is a description add it */
1835         lpNewEnhMetaFileHeader->nDescription=0;
1836         lpNewEnhMetaFileHeader->offDescription=0;
1837
1838         lpNewEnhMetaFileHeader->nHandles = 0; /* No handles yet */
1839         lpNewEnhMetaFileHeader->nRecords = 0;
1840         
1841         /* I am pretty sure this starts at 0 and grows as entries are added */
1842         lpNewEnhMetaFileHeader->nPalEntries = 0;
1843
1844         /* Size in Pixels */
1845         lpNewEnhMetaFileHeader->szlDevice.cx = GetDeviceCaps(hdcRef,HORZRES);
1846         lpNewEnhMetaFileHeader->szlDevice.cy = GetDeviceCaps(hdcRef,VERTRES);
1847
1848         /* Size in mm */
1849         lpNewEnhMetaFileHeader->szlMillimeters.cx =
1850                                         GetDeviceCaps(hdcRef,HORZSIZE);
1851         lpNewEnhMetaFileHeader->szlMillimeters.cy =
1852                                         GetDeviceCaps(hdcRef,VERTSIZE);
1853
1854        /* FIXME: Add in the rest of the fields to the header */
1855        /* cbPixelFormat
1856           offPixelFormat,
1857           bOpenGL */
1858      } 
1859
1860      (char*)lpbBuffer += ((METAHEADER*)lpbBuffer)->mtHeaderSize * 2; /* Point past the header - FIXME: metafile quirk? */ 
1861
1862      /* 2. Enum over individual records and convert them to the new type of records */
1863      while( !bFoundEOF )
1864      { 
1865
1866         LPMETARECORD lpMetaRecord = (LPMETARECORD)lpbBuffer;
1867
1868 #define EMF_ReAllocAndAdjustPointers( a , b ) \
1869                                         { \
1870                                           LPVOID lpTmp; \
1871                                           lpTmp = HeapReAlloc( GetProcessHeap(), 0, \
1872                                                                lpNewEnhMetaFileBuffer, \
1873                                                                uNewEnhMetaFileBufferSize + (b) ); \
1874                                           if( lpTmp == NULL ) { ERR( "No memory!\n" ); goto error; } \
1875                                           lpNewEnhMetaFileBuffer = lpTmp; \
1876                                           lpRecord = (a)( (char*)lpNewEnhMetaFileBuffer + uNewEnhMetaFileBufferSize ); \
1877                                           uNewEnhMetaFileBufferSize += (b); \
1878                                         }
1879
1880         switch( lpMetaRecord->rdFunction )
1881         {
1882           case META_EOF:  
1883           { 
1884              PEMREOF lpRecord;
1885              size_t uRecord = sizeof(*lpRecord);
1886
1887              EMF_ReAllocAndAdjustPointers(PEMREOF,uRecord);
1888               
1889              /* Fill the new record - FIXME: This is not right */
1890              lpRecord->emr.iType = EMR_EOF; 
1891              lpRecord->emr.nSize = sizeof( *lpRecord );
1892              lpRecord->nPalEntries = 0;     /* FIXME */
1893              lpRecord->offPalEntries = 0;   /* FIXME */ 
1894              lpRecord->nSizeLast = 0;       /* FIXME */
1895
1896              /* No more records after this one */
1897              bFoundEOF = TRUE;
1898
1899              FIXME( "META_EOF conversion not correct\n" );
1900              break;
1901           }
1902
1903           case META_SETMAPMODE:
1904           {  
1905              PEMRSETMAPMODE lpRecord;
1906              size_t uRecord = sizeof(*lpRecord);
1907
1908              EMF_ReAllocAndAdjustPointers(PEMRSETMAPMODE,uRecord);
1909
1910              lpRecord->emr.iType = EMR_SETMAPMODE;
1911              lpRecord->emr.nSize = sizeof( *lpRecord );
1912
1913              lpRecord->iMode = lpMetaRecord->rdParm[0];
1914
1915              break;
1916           }
1917
1918           case META_DELETEOBJECT: /* Select and Delete structures are the same */
1919           case META_SELECTOBJECT: 
1920           {
1921             PEMRDELETEOBJECT lpRecord;
1922             size_t uRecord = sizeof(*lpRecord);
1923
1924             EMF_ReAllocAndAdjustPointers(PEMRDELETEOBJECT,uRecord);
1925
1926             if( lpMetaRecord->rdFunction == META_DELETEOBJECT )
1927             {
1928               lpRecord->emr.iType = EMR_DELETEOBJECT;
1929             }
1930             else
1931             {
1932               lpRecord->emr.iType = EMR_SELECTOBJECT;
1933             }
1934             lpRecord->emr.nSize = sizeof( *lpRecord );
1935
1936             lpRecord->ihObject = lpMetaRecord->rdParm[0]; /* FIXME: Handle */
1937
1938             break;
1939           }
1940
1941           case META_POLYGON: /* This is just plain busted. I don't know what I'm doing */
1942           {
1943              PEMRPOLYGON16 lpRecord; /* FIXME: Should it be a poly or poly16? */  
1944              size_t uRecord = sizeof(*lpRecord);
1945
1946              EMF_ReAllocAndAdjustPointers(PEMRPOLYGON16,uRecord);
1947
1948              /* FIXME: This is mostly all wrong */
1949              lpRecord->emr.iType = EMR_POLYGON16;
1950              lpRecord->emr.nSize = sizeof( *lpRecord );
1951
1952              lpRecord->rclBounds.left   = 0;
1953              lpRecord->rclBounds.right  = 0;
1954              lpRecord->rclBounds.top    = 0;
1955              lpRecord->rclBounds.bottom = 0;
1956
1957              lpRecord->cpts = 0;
1958              lpRecord->apts[0].x = 0;
1959              lpRecord->apts[0].y = 0;
1960
1961              FIXME( "META_POLYGON conversion not correct\n" );
1962
1963              break;
1964           }
1965
1966           case META_SETPOLYFILLMODE:
1967           {
1968              PEMRSETPOLYFILLMODE lpRecord;
1969              size_t uRecord = sizeof(*lpRecord);
1970
1971              EMF_ReAllocAndAdjustPointers(PEMRSETPOLYFILLMODE,uRecord);
1972
1973              lpRecord->emr.iType = EMR_SETPOLYFILLMODE;
1974              lpRecord->emr.nSize = sizeof( *lpRecord );
1975
1976              lpRecord->iMode = lpMetaRecord->rdParm[0];
1977              
1978              break;
1979           }
1980
1981           case META_SETWINDOWORG:
1982           {
1983              PEMRSETWINDOWORGEX lpRecord; /* Seems to be the closest thing */
1984              size_t uRecord = sizeof(*lpRecord);
1985
1986              EMF_ReAllocAndAdjustPointers(PEMRSETWINDOWORGEX,uRecord);
1987
1988              lpRecord->emr.iType = EMR_SETWINDOWORGEX;
1989              lpRecord->emr.nSize = sizeof( *lpRecord );
1990
1991              lpRecord->ptlOrigin.x = lpMetaRecord->rdParm[1];
1992              lpRecord->ptlOrigin.y = lpMetaRecord->rdParm[0];
1993
1994              break;
1995           }
1996
1997           case META_SETWINDOWEXT:  /* Structure is the same for SETWINDOWEXT & SETVIEWPORTEXT */
1998           case META_SETVIEWPORTEXT:
1999           {
2000              PEMRSETWINDOWEXTEX lpRecord;
2001              size_t uRecord = sizeof(*lpRecord);
2002
2003              EMF_ReAllocAndAdjustPointers(PEMRSETWINDOWEXTEX,uRecord);
2004
2005              if ( lpMetaRecord->rdFunction == META_SETWINDOWEXT )
2006              {
2007                lpRecord->emr.iType = EMR_SETWINDOWORGEX;
2008              }
2009              else
2010              {
2011                lpRecord->emr.iType = EMR_SETVIEWPORTEXTEX;
2012              }
2013              lpRecord->emr.nSize = sizeof( *lpRecord );
2014
2015              lpRecord->szlExtent.cx = lpMetaRecord->rdParm[1];
2016              lpRecord->szlExtent.cy = lpMetaRecord->rdParm[0];
2017
2018              break;
2019           }
2020
2021           case META_CREATEBRUSHINDIRECT:
2022           {
2023              PEMRCREATEBRUSHINDIRECT lpRecord;
2024              size_t uRecord = sizeof(*lpRecord);
2025
2026              EMF_ReAllocAndAdjustPointers(PEMRCREATEBRUSHINDIRECT,uRecord);
2027
2028              lpRecord->emr.iType = EMR_CREATEBRUSHINDIRECT;
2029              lpRecord->emr.nSize = sizeof( *lpRecord );
2030
2031              lpRecord->ihBrush    = ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nHandles;
2032              lpRecord->lb.lbStyle = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbStyle; 
2033              lpRecord->lb.lbColor = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbColor; 
2034              lpRecord->lb.lbHatch = ((LPLOGBRUSH16)lpMetaRecord->rdParm)->lbHatch; 
2035              
2036              ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nHandles += 1; /* New handle */
2037
2038              break;
2039           }
2040
2041           case META_LINETO:
2042           case META_MOVETO:
2043           {
2044              PEMRLINETO lpRecord;
2045              size_t uRecord = sizeof(*lpRecord);
2046
2047              EMF_ReAllocAndAdjustPointers(PEMRLINETO,uRecord);
2048
2049              if ( lpMetaRecord->rdFunction == META_LINETO )
2050              {
2051                lpRecord->emr.iType = EMR_LINETO;
2052              }
2053              else
2054              {
2055                lpRecord->emr.iType = EMR_MOVETOEX;
2056              }
2057              lpRecord->emr.nSize = sizeof( *lpRecord );
2058
2059              lpRecord->ptl.x = lpMetaRecord->rdParm[1];
2060              lpRecord->ptl.y = lpMetaRecord->rdParm[0];
2061
2062              break;
2063             }
2064
2065           case META_SETTEXTCOLOR:
2066           case META_SETBKCOLOR:
2067           {
2068              PEMRSETBKCOLOR lpRecord;
2069              size_t uRecord = sizeof(*lpRecord);
2070
2071              EMF_ReAllocAndAdjustPointers(PEMRSETBKCOLOR,uRecord);
2072
2073              if ( lpMetaRecord->rdFunction == META_SETTEXTCOLOR )
2074              {
2075                lpRecord->emr.iType = EMR_SETTEXTCOLOR;
2076              }
2077              else
2078              {
2079                lpRecord->emr.iType = EMR_SETBKCOLOR;
2080              }
2081              lpRecord->emr.nSize = sizeof( *lpRecord );
2082
2083              lpRecord->crColor = MAKELONG(lpMetaRecord->rdParm[0],
2084                                     lpMetaRecord->rdParm[1]);
2085
2086              break;
2087           }
2088
2089
2090
2091           /* These are all unimplemented and as such are intended to fall through to the default case */
2092           case META_SETBKMODE:
2093           case META_SETROP2:
2094           case META_SETRELABS:
2095           case META_SETSTRETCHBLTMODE:
2096           case META_SETVIEWPORTORG:
2097           case META_OFFSETWINDOWORG:
2098           case META_SCALEWINDOWEXT:
2099           case META_OFFSETVIEWPORTORG:
2100           case META_SCALEVIEWPORTEXT:
2101           case META_EXCLUDECLIPRECT:
2102           case META_INTERSECTCLIPRECT:
2103           case META_ARC:
2104           case META_ELLIPSE:
2105           case META_FLOODFILL:
2106           case META_PIE:
2107           case META_RECTANGLE:
2108           case META_ROUNDRECT:
2109           case META_PATBLT:
2110           case META_SAVEDC:
2111           case META_SETPIXEL:
2112           case META_OFFSETCLIPRGN:
2113           case META_TEXTOUT:
2114           case META_POLYPOLYGON:
2115           case META_POLYLINE:
2116           case META_RESTOREDC:  
2117           case META_CHORD:
2118           case META_CREATEPATTERNBRUSH:
2119           case META_CREATEPENINDIRECT:
2120           case META_CREATEFONTINDIRECT:
2121           case META_CREATEPALETTE:
2122           case META_SETTEXTALIGN:
2123           case META_SELECTPALETTE:
2124           case META_SETMAPPERFLAGS:
2125           case META_REALIZEPALETTE:
2126           case META_ESCAPE:
2127           case META_EXTTEXTOUT:
2128           case META_STRETCHDIB:
2129           case META_DIBSTRETCHBLT:
2130           case META_STRETCHBLT:
2131           case META_BITBLT:
2132           case META_CREATEREGION:
2133           case META_FILLREGION:
2134           case META_FRAMEREGION:
2135           case META_INVERTREGION:
2136           case META_PAINTREGION:
2137           case META_SELECTCLIPREGION:
2138           case META_DIBCREATEPATTERNBRUSH:
2139           case META_DIBBITBLT:
2140           case META_SETTEXTCHAREXTRA:
2141           case META_SETTEXTJUSTIFICATION:
2142           case META_EXTFLOODFILL:
2143           case META_SETDIBTODEV:
2144           case META_DRAWTEXT:
2145           case META_ANIMATEPALETTE:
2146           case META_SETPALENTRIES:
2147           case META_RESIZEPALETTE:
2148           case META_RESETDC:
2149           case META_STARTDOC:
2150           case META_STARTPAGE:
2151           case META_ENDPAGE:
2152           case META_ABORTDOC:
2153           case META_ENDDOC:
2154           case META_CREATEBRUSH:
2155           case META_CREATEBITMAPINDIRECT:
2156           case META_CREATEBITMAP:    
2157           /* Fall through to unimplemented */
2158           default:
2159           {
2160             /* Not implemented yet */
2161             FIXME( "Conversion of record type 0x%x not implemented.\n", lpMetaRecord->rdFunction );
2162             break;
2163           }
2164        }
2165
2166        /* Move to the next record */
2167        (char*)lpbBuffer += ((LPMETARECORD)lpbBuffer)->rdSize * 2; /* FIXME: Seem to be doing this in metafile.c */ 
2168
2169 #undef ReAllocAndAdjustPointers
2170      } 
2171
2172      /* We know the last of the header information now */
2173      ((LPENHMETAHEADER)lpNewEnhMetaFileBuffer)->nBytes = uNewEnhMetaFileBufferSize;
2174
2175      /* Create the enhanced metafile */
2176      hMf = SetEnhMetaFileBits( uNewEnhMetaFileBufferSize, (const BYTE*)lpNewEnhMetaFileBuffer ); 
2177
2178      if( !hMf )
2179        ERR( "Problem creating metafile. Did the conversion fail somewhere?\n" );
2180
2181      return hMf;
2182
2183 error:
2184      /* Free the data associated with our copy since it's been copied */
2185      HeapFree( GetProcessHeap(), 0, lpNewEnhMetaFileBuffer ); 
2186
2187      return 0;  
2188 }
2189
2190
2191