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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "config.h"
35 #include "wine/port.h"
36
37 #include <stdarg.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <assert.h>
41 #include "windef.h"
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"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
50
51
52 static CRITICAL_SECTION enhmetafile_cs;
53 static CRITICAL_SECTION_DEBUG critsect_debug =
54 {
55 0, 0, &enhmetafile_cs,
56 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
57 0, 0, { (DWORD_PTR)(__FILE__ ": enhmetafile_cs") }
58 };
59 static CRITICAL_SECTION enhmetafile_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
60
61 typedef struct
62 {
63 ENHMETAHEADER *emh;
64 BOOL on_disk; /* true if metafile is on disk */
65 } ENHMETAFILEOBJ;
66
67 static const struct emr_name {
68 DWORD type;
69 const char *name;
70 } emr_names[] = {
71 #define X(p) {p, #p}
72 X(EMR_HEADER),
73 X(EMR_POLYBEZIER),
74 X(EMR_POLYGON),
75 X(EMR_POLYLINE),
76 X(EMR_POLYBEZIERTO),
77 X(EMR_POLYLINETO),
78 X(EMR_POLYPOLYLINE),
79 X(EMR_POLYPOLYGON),
80 X(EMR_SETWINDOWEXTEX),
81 X(EMR_SETWINDOWORGEX),
82 X(EMR_SETVIEWPORTEXTEX),
83 X(EMR_SETVIEWPORTORGEX),
84 X(EMR_SETBRUSHORGEX),
85 X(EMR_EOF),
86 X(EMR_SETPIXELV),
87 X(EMR_SETMAPPERFLAGS),
88 X(EMR_SETMAPMODE),
89 X(EMR_SETBKMODE),
90 X(EMR_SETPOLYFILLMODE),
91 X(EMR_SETROP2),
92 X(EMR_SETSTRETCHBLTMODE),
93 X(EMR_SETTEXTALIGN),
94 X(EMR_SETCOLORADJUSTMENT),
95 X(EMR_SETTEXTCOLOR),
96 X(EMR_SETBKCOLOR),
97 X(EMR_OFFSETCLIPRGN),
98 X(EMR_MOVETOEX),
99 X(EMR_SETMETARGN),
100 X(EMR_EXCLUDECLIPRECT),
101 X(EMR_INTERSECTCLIPRECT),
102 X(EMR_SCALEVIEWPORTEXTEX),
103 X(EMR_SCALEWINDOWEXTEX),
104 X(EMR_SAVEDC),
105 X(EMR_RESTOREDC),
106 X(EMR_SETWORLDTRANSFORM),
107 X(EMR_MODIFYWORLDTRANSFORM),
108 X(EMR_SELECTOBJECT),
109 X(EMR_CREATEPEN),
110 X(EMR_CREATEBRUSHINDIRECT),
111 X(EMR_DELETEOBJECT),
112 X(EMR_ANGLEARC),
113 X(EMR_ELLIPSE),
114 X(EMR_RECTANGLE),
115 X(EMR_ROUNDRECT),
116 X(EMR_ARC),
117 X(EMR_CHORD),
118 X(EMR_PIE),
119 X(EMR_SELECTPALETTE),
120 X(EMR_CREATEPALETTE),
121 X(EMR_SETPALETTEENTRIES),
122 X(EMR_RESIZEPALETTE),
123 X(EMR_REALIZEPALETTE),
124 X(EMR_EXTFLOODFILL),
125 X(EMR_LINETO),
126 X(EMR_ARCTO),
127 X(EMR_POLYDRAW),
128 X(EMR_SETARCDIRECTION),
129 X(EMR_SETMITERLIMIT),
130 X(EMR_BEGINPATH),
131 X(EMR_ENDPATH),
132 X(EMR_CLOSEFIGURE),
133 X(EMR_FILLPATH),
134 X(EMR_STROKEANDFILLPATH),
135 X(EMR_STROKEPATH),
136 X(EMR_FLATTENPATH),
137 X(EMR_WIDENPATH),
138 X(EMR_SELECTCLIPPATH),
139 X(EMR_ABORTPATH),
140 X(EMR_GDICOMMENT),
141 X(EMR_FILLRGN),
142 X(EMR_FRAMERGN),
143 X(EMR_INVERTRGN),
144 X(EMR_PAINTRGN),
145 X(EMR_EXTSELECTCLIPRGN),
146 X(EMR_BITBLT),
147 X(EMR_STRETCHBLT),
148 X(EMR_MASKBLT),
149 X(EMR_PLGBLT),
150 X(EMR_SETDIBITSTODEVICE),
151 X(EMR_STRETCHDIBITS),
152 X(EMR_EXTCREATEFONTINDIRECTW),
153 X(EMR_EXTTEXTOUTA),
154 X(EMR_EXTTEXTOUTW),
155 X(EMR_POLYBEZIER16),
156 X(EMR_POLYGON16),
157 X(EMR_POLYLINE16),
158 X(EMR_POLYBEZIERTO16),
159 X(EMR_POLYLINETO16),
160 X(EMR_POLYPOLYLINE16),
161 X(EMR_POLYPOLYGON16),
162 X(EMR_POLYDRAW16),
163 X(EMR_CREATEMONOBRUSH),
164 X(EMR_CREATEDIBPATTERNBRUSHPT),
165 X(EMR_EXTCREATEPEN),
166 X(EMR_POLYTEXTOUTA),
167 X(EMR_POLYTEXTOUTW),
168 X(EMR_SETICMMODE),
169 X(EMR_CREATECOLORSPACE),
170 X(EMR_SETCOLORSPACE),
171 X(EMR_DELETECOLORSPACE),
172 X(EMR_GLSRECORD),
173 X(EMR_GLSBOUNDEDRECORD),
174 X(EMR_PIXELFORMAT),
175 X(EMR_DRAWESCAPE),
176 X(EMR_EXTESCAPE),
177 X(EMR_STARTDOC),
178 X(EMR_SMALLTEXTOUT),
179 X(EMR_FORCEUFIMAPPING),
180 X(EMR_NAMEDESCAPE),
181 X(EMR_COLORCORRECTPALETTE),
182 X(EMR_SETICMPROFILEA),
183 X(EMR_SETICMPROFILEW),
184 X(EMR_ALPHABLEND),
185 X(EMR_SETLAYOUT),
186 X(EMR_TRANSPARENTBLT),
187 X(EMR_RESERVED_117),
188 X(EMR_GRADIENTFILL),
189 X(EMR_SETLINKEDUFI),
190 X(EMR_SETTEXTJUSTIFICATION),
191 X(EMR_COLORMATCHTOTARGETW),
192 X(EMR_CREATECOLORSPACEW)
193 #undef X
194 };
195
196 /****************************************************************************
197 * get_emr_name
198 */
get_emr_name(DWORD type)199 static const char *get_emr_name(DWORD type)
200 {
201 unsigned int i;
202 for(i = 0; i < sizeof(emr_names) / sizeof(emr_names[0]); i++)
203 if(type == emr_names[i].type) return emr_names[i].name;
204 TRACE("Unknown record type %d\n", type);
205 return NULL;
206 }
207
208 /***********************************************************************
209 * is_dib_monochrome
210 *
211 * Returns whether a DIB can be converted to a monochrome DDB.
212 *
213 * A DIB can be converted if its color table contains only black and
214 * white. Black must be the first color in the color table.
215 *
216 * Note : If the first color in the color table is white followed by
217 * black, we can't convert it to a monochrome DDB with
218 * SetDIBits, because black and white would be inverted.
219 */
is_dib_monochrome(const BITMAPINFO * info)220 static inline BOOL is_dib_monochrome( const BITMAPINFO* info )
221 {
222 if (info->bmiHeader.biBitCount != 1) return FALSE;
223
224 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
225 {
226 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO *) info)->bmciColors;
227
228 /* Check if the first color is black */
229 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
230 {
231 rgb++;
232 /* Check if the second color is white */
233 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
234 && (rgb->rgbtBlue == 0xff));
235 }
236 else return FALSE;
237 }
238 else /* assume BITMAPINFOHEADER */
239 {
240 const RGBQUAD *rgb = info->bmiColors;
241
242 /* Check if the first color is black */
243 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
244 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
245 {
246 rgb++;
247
248 /* Check if the second color is white */
249 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
250 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
251 }
252 else return FALSE;
253 }
254 }
255
256 /****************************************************************************
257 * EMF_Create_HENHMETAFILE
258 */
EMF_Create_HENHMETAFILE(ENHMETAHEADER * emh,DWORD filesize,BOOL on_disk)259 HENHMETAFILE EMF_Create_HENHMETAFILE(ENHMETAHEADER *emh, DWORD filesize, BOOL on_disk )
260 {
261 HENHMETAFILE hmf;
262 ENHMETAFILEOBJ *metaObj;
263
264 if (emh->iType != EMR_HEADER)
265 {
266 SetLastError(ERROR_INVALID_DATA);
267 return 0;
268 }
269 if (emh->dSignature != ENHMETA_SIGNATURE ||
270 (emh->nBytes & 3)) /* refuse to load unaligned EMF as Windows does */
271 {
272 WARN("Invalid emf header type 0x%08x sig 0x%08x.\n",
273 emh->iType, emh->dSignature);
274 return 0;
275 }
276 if (filesize < emh->nBytes)
277 {
278 WARN("File truncated (got %u bytes, header says %u)\n", emh->nBytes, filesize);
279 return 0;
280 }
281
282 if (!(metaObj = HeapAlloc( GetProcessHeap(), 0, sizeof(*metaObj) ))) return 0;
283
284 metaObj->emh = emh;
285 metaObj->on_disk = on_disk;
286
287 if (!(hmf = alloc_gdi_handle( metaObj, OBJ_ENHMETAFILE, NULL )))
288 HeapFree( GetProcessHeap(), 0, metaObj );
289 return hmf;
290 }
291
292 /****************************************************************************
293 * EMF_Delete_HENHMETAFILE
294 */
EMF_Delete_HENHMETAFILE(HENHMETAFILE hmf)295 static BOOL EMF_Delete_HENHMETAFILE( HENHMETAFILE hmf )
296 {
297 ENHMETAFILEOBJ *metaObj;
298 BOOL Ret = FALSE;
299
300 EnterCriticalSection( &enhmetafile_cs );
301 metaObj = free_gdi_handle( hmf );
302 if(metaObj)
303 {
304 if(metaObj->on_disk)
305 UnmapViewOfFile( metaObj->emh );
306 else
307 HeapFree( GetProcessHeap(), 0, metaObj->emh );
308 HeapFree( GetProcessHeap(), 0, metaObj );
309 Ret = TRUE;
310 }
311 LeaveCriticalSection( &enhmetafile_cs );
312 return Ret;
313 }
314
315 /******************************************************************
316 * EMF_GetEnhMetaHeader
317 *
318 * Returns ptr to ENHMETAHEADER associated with HENHMETAFILE
319 */
EMF_GetEnhMetaHeader(HENHMETAFILE hmf)320 static ENHMETAHEADER *EMF_GetEnhMetaHeader( HENHMETAFILE hmf )
321 {
322 ENHMETAHEADER *ret = NULL;
323 ENHMETAFILEOBJ *metaObj;
324
325 EnterCriticalSection( &enhmetafile_cs );
326 metaObj = GDI_GetObjPtr( hmf, OBJ_ENHMETAFILE );
327 TRACE("hmf %p -> enhmetaObj %p\n", hmf, metaObj);
328 if (metaObj)
329 {
330 ret = metaObj->emh;
331 GDI_ReleaseObj( hmf );
332 }
333 LeaveCriticalSection( &enhmetafile_cs );
334 return ret;
335 }
336
337 /*****************************************************************************
338 * EMF_GetEnhMetaFile
339 *
340 */
EMF_GetEnhMetaFile(HANDLE hFile)341 static HENHMETAFILE EMF_GetEnhMetaFile( HANDLE hFile )
342 {
343 ENHMETAHEADER *emh;
344 HANDLE hMapping;
345 HENHMETAFILE hemf;
346 DWORD filesize;
347
348 filesize = GetFileSize( hFile, NULL );
349
350 hMapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
351 emh = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
352 CloseHandle( hMapping );
353
354 if (!emh) return 0;
355
356 hemf = EMF_Create_HENHMETAFILE( emh, filesize, TRUE );
357 if (!hemf)
358 UnmapViewOfFile( emh );
359 return hemf;
360 }
361
362
363 /*****************************************************************************
364 * GetEnhMetaFileA (GDI32.@)
365 *
366 *
367 */
GetEnhMetaFileA(LPCSTR lpszMetaFile)368 HENHMETAFILE WINAPI GetEnhMetaFileA(
369 LPCSTR lpszMetaFile /* [in] filename of enhanced metafile */
370 )
371 {
372 HENHMETAFILE hmf;
373 HANDLE hFile;
374
375 hFile = CreateFileA(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
376 OPEN_EXISTING, 0, 0);
377 if (hFile == INVALID_HANDLE_VALUE) {
378 WARN("could not open %s\n", lpszMetaFile);
379 return 0;
380 }
381 hmf = EMF_GetEnhMetaFile( hFile );
382 CloseHandle( hFile );
383 return hmf;
384 }
385
386 /*****************************************************************************
387 * GetEnhMetaFileW (GDI32.@)
388 */
GetEnhMetaFileW(LPCWSTR lpszMetaFile)389 HENHMETAFILE WINAPI GetEnhMetaFileW(
390 LPCWSTR lpszMetaFile) /* [in] filename of enhanced metafile */
391 {
392 HENHMETAFILE hmf;
393 HANDLE hFile;
394
395 hFile = CreateFileW(lpszMetaFile, GENERIC_READ, FILE_SHARE_READ, 0,
396 OPEN_EXISTING, 0, 0);
397 if (hFile == INVALID_HANDLE_VALUE) {
398 WARN("could not open %s\n", debugstr_w(lpszMetaFile));
399 return 0;
400 }
401 hmf = EMF_GetEnhMetaFile( hFile );
402 CloseHandle( hFile );
403 return hmf;
404 }
405
406 /*****************************************************************************
407 * GetEnhMetaFileHeader (GDI32.@)
408 *
409 * Retrieves the record containing the header for the specified
410 * enhanced-format metafile.
411 *
412 * RETURNS
413 * If buf is NULL, returns the size of buffer required.
414 * Otherwise, copy up to bufsize bytes of enhanced metafile header into
415 * buf.
416 */
GetEnhMetaFileHeader(HENHMETAFILE hmf,UINT bufsize,LPENHMETAHEADER buf)417 UINT WINAPI GetEnhMetaFileHeader(
418 HENHMETAFILE hmf, /* [in] enhanced metafile */
419 UINT bufsize, /* [in] size of buffer */
420 LPENHMETAHEADER buf /* [out] buffer */
421 )
422 {
423 LPENHMETAHEADER emh;
424 UINT size;
425
426 emh = EMF_GetEnhMetaHeader(hmf);
427 if(!emh) return FALSE;
428 size = emh->nSize;
429 if (!buf) return size;
430 size = min(size, bufsize);
431 memmove(buf, emh, size);
432 return size;
433 }
434
435
436 /*****************************************************************************
437 * GetEnhMetaFileDescriptionA (GDI32.@)
438 *
439 * See GetEnhMetaFileDescriptionW.
440 */
GetEnhMetaFileDescriptionA(HENHMETAFILE hmf,UINT size,LPSTR buf)441 UINT WINAPI GetEnhMetaFileDescriptionA(
442 HENHMETAFILE hmf, /* [in] enhanced metafile */
443 UINT size, /* [in] size of buf */
444 LPSTR buf /* [out] buffer to receive description */
445 )
446 {
447 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
448 DWORD len;
449 WCHAR *descrW;
450
451 if(!emh) return FALSE;
452 if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
453 descrW = (WCHAR *) ((char *) emh + emh->offDescription);
454 len = WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, NULL, 0, NULL, NULL );
455
456 if (!buf || !size ) return len;
457
458 len = min( size, len );
459 WideCharToMultiByte( CP_ACP, 0, descrW, emh->nDescription, buf, len, NULL, NULL );
460 return len;
461 }
462
463 /*****************************************************************************
464 * GetEnhMetaFileDescriptionW (GDI32.@)
465 *
466 * Copies the description string of an enhanced metafile into a buffer
467 * _buf_.
468 *
469 * RETURNS
470 * If _buf_ is NULL, returns size of _buf_ required. Otherwise, returns
471 * number of characters copied.
472 */
GetEnhMetaFileDescriptionW(HENHMETAFILE hmf,UINT size,LPWSTR buf)473 UINT WINAPI GetEnhMetaFileDescriptionW(
474 HENHMETAFILE hmf, /* [in] enhanced metafile */
475 UINT size, /* [in] size of buf */
476 LPWSTR buf /* [out] buffer to receive description */
477 )
478 {
479 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader(hmf);
480
481 if(!emh) return FALSE;
482 if(emh->nDescription == 0 || emh->offDescription == 0) return 0;
483 if (!buf || !size ) return emh->nDescription;
484
485 memmove(buf, (char *) emh + emh->offDescription, min(size,emh->nDescription)*sizeof(WCHAR));
486 return min(size, emh->nDescription);
487 }
488
489 /****************************************************************************
490 * SetEnhMetaFileBits (GDI32.@)
491 *
492 * Creates an enhanced metafile by copying _bufsize_ bytes from _buf_.
493 */
SetEnhMetaFileBits(UINT bufsize,const BYTE * buf)494 HENHMETAFILE WINAPI SetEnhMetaFileBits(UINT bufsize, const BYTE *buf)
495 {
496 ENHMETAHEADER *emh = HeapAlloc( GetProcessHeap(), 0, bufsize );
497 HENHMETAFILE hmf;
498 memmove(emh, buf, bufsize);
499 hmf = EMF_Create_HENHMETAFILE( emh, bufsize, FALSE );
500 if (!hmf)
501 HeapFree( GetProcessHeap(), 0, emh );
502 return hmf;
503 }
504
505 /*****************************************************************************
506 * GetEnhMetaFileBits (GDI32.@)
507 *
508 */
GetEnhMetaFileBits(HENHMETAFILE hmf,UINT bufsize,LPBYTE buf)509 UINT WINAPI GetEnhMetaFileBits(
510 HENHMETAFILE hmf,
511 UINT bufsize,
512 LPBYTE buf
513 )
514 {
515 LPENHMETAHEADER emh = EMF_GetEnhMetaHeader( hmf );
516 UINT size;
517
518 if(!emh) return 0;
519
520 size = emh->nBytes;
521 if( buf == NULL ) return size;
522
523 size = min( size, bufsize );
524 memmove(buf, emh, size);
525 return size;
526 }
527
528 typedef struct EMF_dc_state
529 {
530 INT mode;
531 XFORM world_transform;
532 INT wndOrgX;
533 INT wndOrgY;
534 INT wndExtX;
535 INT wndExtY;
536 INT vportOrgX;
537 INT vportOrgY;
538 INT vportExtX;
539 INT vportExtY;
540 struct EMF_dc_state *next;
541 } EMF_dc_state;
542
543 typedef struct enum_emh_data
544 {
545 XFORM init_transform;
546 EMF_dc_state state;
547 INT save_level;
548 EMF_dc_state *saved_state;
549 } enum_emh_data;
550
551 #define ENUM_GET_PRIVATE_DATA(ht) \
552 ((enum_emh_data*)(((unsigned char*)(ht))-sizeof (enum_emh_data)))
553
554 #define WIDTH(rect) ( (rect).right - (rect).left )
555 #define HEIGHT(rect) ( (rect).bottom - (rect).top )
556
557 #define IS_WIN9X() (GetVersion()&0x80000000)
558
EMF_Update_MF_Xform(HDC hdc,const enum_emh_data * info)559 static void EMF_Update_MF_Xform(HDC hdc, const enum_emh_data *info)
560 {
561 XFORM mapping_mode_trans, final_trans;
562 double scaleX, scaleY;
563
564 scaleX = (double)info->state.vportExtX / (double)info->state.wndExtX;
565 scaleY = (double)info->state.vportExtY / (double)info->state.wndExtY;
566 mapping_mode_trans.eM11 = scaleX;
567 mapping_mode_trans.eM12 = 0.0;
568 mapping_mode_trans.eM21 = 0.0;
569 mapping_mode_trans.eM22 = scaleY;
570 mapping_mode_trans.eDx = (double)info->state.vportOrgX - scaleX * (double)info->state.wndOrgX;
571 mapping_mode_trans.eDy = (double)info->state.vportOrgY - scaleY * (double)info->state.wndOrgY;
572
573 CombineTransform(&final_trans, &info->state.world_transform, &mapping_mode_trans);
574 CombineTransform(&final_trans, &final_trans, &info->init_transform);
575
576 if (!SetWorldTransform(hdc, &final_trans))
577 {
578 ERR("World transform failed!\n");
579 }
580 }
581
EMF_RestoreDC(enum_emh_data * info,INT level)582 static void EMF_RestoreDC( enum_emh_data *info, INT level )
583 {
584 if (abs(level) > info->save_level || level == 0) return;
585
586 if (level < 0) level = info->save_level + level + 1;
587
588 while (info->save_level >= level)
589 {
590 EMF_dc_state *state = info->saved_state;
591 info->saved_state = state->next;
592 state->next = NULL;
593 if (--info->save_level < level)
594 info->state = *state;
595 HeapFree( GetProcessHeap(), 0, state );
596 }
597 }
598
EMF_SaveDC(enum_emh_data * info)599 static void EMF_SaveDC( enum_emh_data *info )
600 {
601 EMF_dc_state *state = HeapAlloc( GetProcessHeap(), 0, sizeof(*state));
602 if (state)
603 {
604 *state = info->state;
605 state->next = info->saved_state;
606 info->saved_state = state;
607 info->save_level++;
608 TRACE("save_level %d\n", info->save_level);
609 }
610 }
611
EMF_SetMapMode(HDC hdc,enum_emh_data * info)612 static void EMF_SetMapMode(HDC hdc, enum_emh_data *info)
613 {
614 INT horzSize = GetDeviceCaps( hdc, HORZSIZE );
615 INT vertSize = GetDeviceCaps( hdc, VERTSIZE );
616 INT horzRes = GetDeviceCaps( hdc, HORZRES );
617 INT vertRes = GetDeviceCaps( hdc, VERTRES );
618
619 TRACE("%d\n", info->state.mode);
620
621 switch(info->state.mode)
622 {
623 case MM_TEXT:
624 info->state.wndExtX = 1;
625 info->state.wndExtY = 1;
626 info->state.vportExtX = 1;
627 info->state.vportExtY = 1;
628 break;
629 case MM_LOMETRIC:
630 case MM_ISOTROPIC:
631 info->state.wndExtX = horzSize * 10;
632 info->state.wndExtY = vertSize * 10;
633 info->state.vportExtX = horzRes;
634 info->state.vportExtY = -vertRes;
635 break;
636 case MM_HIMETRIC:
637 info->state.wndExtX = horzSize * 100;
638 info->state.wndExtY = vertSize * 100;
639 info->state.vportExtX = horzRes;
640 info->state.vportExtY = -vertRes;
641 break;
642 case MM_LOENGLISH:
643 info->state.wndExtX = MulDiv(1000, horzSize, 254);
644 info->state.wndExtY = MulDiv(1000, vertSize, 254);
645 info->state.vportExtX = horzRes;
646 info->state.vportExtY = -vertRes;
647 break;
648 case MM_HIENGLISH:
649 info->state.wndExtX = MulDiv(10000, horzSize, 254);
650 info->state.wndExtY = MulDiv(10000, vertSize, 254);
651 info->state.vportExtX = horzRes;
652 info->state.vportExtY = -vertRes;
653 break;
654 case MM_TWIPS:
655 info->state.wndExtX = MulDiv(14400, horzSize, 254);
656 info->state.wndExtY = MulDiv(14400, vertSize, 254);
657 info->state.vportExtX = horzRes;
658 info->state.vportExtY = -vertRes;
659 break;
660 case MM_ANISOTROPIC:
661 break;
662 default:
663 return;
664 }
665 }
666
667 /***********************************************************************
668 * EMF_FixIsotropic
669 *
670 * Fix viewport extensions for isotropic mode.
671 */
672
EMF_FixIsotropic(HDC hdc,enum_emh_data * info)673 static void EMF_FixIsotropic(HDC hdc, enum_emh_data *info)
674 {
675 double xdim = fabs((double)info->state.vportExtX * GetDeviceCaps( hdc, HORZSIZE ) /
676 (GetDeviceCaps( hdc, HORZRES ) * info->state.wndExtX));
677 double ydim = fabs((double)info->state.vportExtY * GetDeviceCaps( hdc, VERTSIZE ) /
678 (GetDeviceCaps( hdc, VERTRES ) * info->state.wndExtY));
679
680 if (xdim > ydim)
681 {
682 INT mincx = (info->state.vportExtX >= 0) ? 1 : -1;
683 info->state.vportExtX = floor(info->state.vportExtX * ydim / xdim + 0.5);
684 if (!info->state.vportExtX) info->state.vportExtX = mincx;
685 }
686 else
687 {
688 INT mincy = (info->state.vportExtY >= 0) ? 1 : -1;
689 info->state.vportExtY = floor(info->state.vportExtY * xdim / ydim + 0.5);
690 if (!info->state.vportExtY) info->state.vportExtY = mincy;
691 }
692 }
693
694 /*****************************************************************************
695 * emr_produces_output
696 *
697 * Returns TRUE if the record type writes something to the dc. Used by
698 * PlayEnhMetaFileRecord to determine whether it needs to update the
699 * dc's xform when in win9x mode.
700 *
701 * FIXME: need to test which records should be here.
702 */
emr_produces_output(int type)703 static BOOL emr_produces_output(int type)
704 {
705 switch(type) {
706 case EMR_POLYBEZIER:
707 case EMR_POLYGON:
708 case EMR_POLYLINE:
709 case EMR_POLYBEZIERTO:
710 case EMR_POLYLINETO:
711 case EMR_POLYPOLYLINE:
712 case EMR_POLYPOLYGON:
713 case EMR_SETPIXELV:
714 case EMR_MOVETOEX:
715 case EMR_EXCLUDECLIPRECT:
716 case EMR_INTERSECTCLIPRECT:
717 case EMR_SELECTOBJECT:
718 case EMR_ANGLEARC:
719 case EMR_ELLIPSE:
720 case EMR_RECTANGLE:
721 case EMR_ROUNDRECT:
722 case EMR_ARC:
723 case EMR_CHORD:
724 case EMR_PIE:
725 case EMR_EXTFLOODFILL:
726 case EMR_LINETO:
727 case EMR_ARCTO:
728 case EMR_POLYDRAW:
729 case EMR_GDICOMMENT:
730 case EMR_FILLRGN:
731 case EMR_FRAMERGN:
732 case EMR_INVERTRGN:
733 case EMR_PAINTRGN:
734 case EMR_BITBLT:
735 case EMR_STRETCHBLT:
736 case EMR_MASKBLT:
737 case EMR_PLGBLT:
738 case EMR_SETDIBITSTODEVICE:
739 case EMR_STRETCHDIBITS:
740 case EMR_EXTTEXTOUTA:
741 case EMR_EXTTEXTOUTW:
742 case EMR_POLYBEZIER16:
743 case EMR_POLYGON16:
744 case EMR_POLYLINE16:
745 case EMR_POLYBEZIERTO16:
746 case EMR_POLYLINETO16:
747 case EMR_POLYPOLYLINE16:
748 case EMR_POLYPOLYGON16:
749 case EMR_POLYDRAW16:
750 case EMR_POLYTEXTOUTA:
751 case EMR_POLYTEXTOUTW:
752 case EMR_SMALLTEXTOUT:
753 case EMR_ALPHABLEND:
754 case EMR_TRANSPARENTBLT:
755 return TRUE;
756 default:
757 return FALSE;
758 }
759 }
760
761
762 /*****************************************************************************
763 * PlayEnhMetaFileRecord (GDI32.@)
764 *
765 * Render a single enhanced metafile record in the device context hdc.
766 *
767 * RETURNS
768 * TRUE (non zero) on success, FALSE on error.
769 * BUGS
770 * Many unimplemented records.
771 * No error handling on record play failures (ie checking return codes)
772 *
773 * NOTES
774 * WinNT actually updates the current world transform in this function
775 * whereas Win9x does not.
776 */
PlayEnhMetaFileRecord(HDC hdc,LPHANDLETABLE handletable,const ENHMETARECORD * mr,UINT handles)777 BOOL WINAPI PlayEnhMetaFileRecord(
778 HDC hdc, /* [in] device context in which to render EMF record */
779 LPHANDLETABLE handletable, /* [in] array of handles to be used in rendering record */
780 const ENHMETARECORD *mr, /* [in] EMF record to render */
781 UINT handles /* [in] size of handle array */
782 )
783 {
784 int type;
785 RECT tmprc;
786 enum_emh_data *info = ENUM_GET_PRIVATE_DATA(handletable);
787
788 TRACE("hdc = %p, handletable = %p, record = %p, numHandles = %d\n",
789 hdc, handletable, mr, handles);
790 if (!mr) return FALSE;
791
792 type = mr->iType;
793
794 TRACE("record %s\n", get_emr_name(type));
795 switch(type)
796 {
797 case EMR_HEADER:
798 break;
799 case EMR_EOF:
800 break;
801 case EMR_GDICOMMENT:
802 {
803 const EMRGDICOMMENT *lpGdiComment = (const EMRGDICOMMENT *)mr;
804 /* In an enhanced metafile, there can be both public and private GDI comments */
805 GdiComment( hdc, lpGdiComment->cbData, lpGdiComment->Data );
806 break;
807 }
808 case EMR_SETMAPMODE:
809 {
810 const EMRSETMAPMODE *pSetMapMode = (const EMRSETMAPMODE *)mr;
811
812 if (info->state.mode == pSetMapMode->iMode &&
813 (info->state.mode == MM_ISOTROPIC || info->state.mode == MM_ANISOTROPIC))
814 break;
815 info->state.mode = pSetMapMode->iMode;
816 EMF_SetMapMode(hdc, info);
817
818 if (!IS_WIN9X())
819 EMF_Update_MF_Xform(hdc, info);
820
821 break;
822 }
823 case EMR_SETBKMODE:
824 {
825 const EMRSETBKMODE *pSetBkMode = (const EMRSETBKMODE *)mr;
826 SetBkMode(hdc, pSetBkMode->iMode);
827 break;
828 }
829 case EMR_SETBKCOLOR:
830 {
831 const EMRSETBKCOLOR *pSetBkColor = (const EMRSETBKCOLOR *)mr;
832 SetBkColor(hdc, pSetBkColor->crColor);
833 break;
834 }
835 case EMR_SETPOLYFILLMODE:
836 {
837 const EMRSETPOLYFILLMODE *pSetPolyFillMode = (const EMRSETPOLYFILLMODE *)mr;
838 SetPolyFillMode(hdc, pSetPolyFillMode->iMode);
839 break;
840 }
841 case EMR_SETROP2:
842 {
843 const EMRSETROP2 *pSetROP2 = (const EMRSETROP2 *)mr;
844 SetROP2(hdc, pSetROP2->iMode);
845 break;
846 }
847 case EMR_SETSTRETCHBLTMODE:
848 {
849 const EMRSETSTRETCHBLTMODE *pSetStretchBltMode = (const EMRSETSTRETCHBLTMODE *)mr;
850 SetStretchBltMode(hdc, pSetStretchBltMode->iMode);
851 break;
852 }
853 case EMR_SETTEXTALIGN:
854 {
855 const EMRSETTEXTALIGN *pSetTextAlign = (const EMRSETTEXTALIGN *)mr;
856 SetTextAlign(hdc, pSetTextAlign->iMode);
857 break;
858 }
859 case EMR_SETTEXTCOLOR:
860 {
861 const EMRSETTEXTCOLOR *pSetTextColor = (const EMRSETTEXTCOLOR *)mr;
862 SetTextColor(hdc, pSetTextColor->crColor);
863 break;
864 }
865 case EMR_SAVEDC:
866 {
867 if (SaveDC( hdc ))
868 EMF_SaveDC( info );
869 break;
870 }
871 case EMR_RESTOREDC:
872 {
873 const EMRRESTOREDC *pRestoreDC = (const EMRRESTOREDC *)mr;
874 TRACE("EMR_RESTORE: %d\n", pRestoreDC->iRelative);
875 if (RestoreDC( hdc, pRestoreDC->iRelative ))
876 EMF_RestoreDC( info, pRestoreDC->iRelative );
877 break;
878 }
879 case EMR_INTERSECTCLIPRECT:
880 {
881 const EMRINTERSECTCLIPRECT *pClipRect = (const EMRINTERSECTCLIPRECT *)mr;
882 TRACE("EMR_INTERSECTCLIPRECT: rect %d,%d - %d, %d\n",
883 pClipRect->rclClip.left, pClipRect->rclClip.top,
884 pClipRect->rclClip.right, pClipRect->rclClip.bottom);
885 IntersectClipRect(hdc, pClipRect->rclClip.left, pClipRect->rclClip.top,
886 pClipRect->rclClip.right, pClipRect->rclClip.bottom);
887 break;
888 }
889 case EMR_SELECTOBJECT:
890 {
891 const EMRSELECTOBJECT *pSelectObject = (const EMRSELECTOBJECT *)mr;
892 if( pSelectObject->ihObject & 0x80000000 ) {
893 /* High order bit is set - it's a stock object
894 * Strip the high bit to get the index.
895 * See MSDN article Q142319
896 */
897 SelectObject( hdc, GetStockObject( pSelectObject->ihObject &
898 0x7fffffff ) );
899 } else {
900 /* High order bit wasn't set - not a stock object
901 */
902 SelectObject( hdc,
903 (handletable->objectHandle)[pSelectObject->ihObject] );
904 }
905 break;
906 }
907 case EMR_DELETEOBJECT:
908 {
909 const EMRDELETEOBJECT *pDeleteObject = (const EMRDELETEOBJECT *)mr;
910 DeleteObject( (handletable->objectHandle)[pDeleteObject->ihObject]);
911 (handletable->objectHandle)[pDeleteObject->ihObject] = 0;
912 break;
913 }
914 case EMR_SETWINDOWORGEX:
915 {
916 const EMRSETWINDOWORGEX *pSetWindowOrgEx = (const EMRSETWINDOWORGEX *)mr;
917
918 info->state.wndOrgX = pSetWindowOrgEx->ptlOrigin.x;
919 info->state.wndOrgY = pSetWindowOrgEx->ptlOrigin.y;
920
921 TRACE("SetWindowOrgEx: %d,%d\n", info->state.wndOrgX, info->state.wndOrgY);
922
923 if (!IS_WIN9X())
924 EMF_Update_MF_Xform(hdc, info);
925
926 break;
927 }
928 case EMR_SETWINDOWEXTEX:
929 {
930 const EMRSETWINDOWEXTEX *pSetWindowExtEx = (const EMRSETWINDOWEXTEX *)mr;
931
932 if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
933 break;
934 info->state.wndExtX = pSetWindowExtEx->szlExtent.cx;
935 info->state.wndExtY = pSetWindowExtEx->szlExtent.cy;
936 if (info->state.mode == MM_ISOTROPIC)
937 EMF_FixIsotropic(hdc, info);
938
939 TRACE("SetWindowExtEx: %d,%d\n",info->state.wndExtX, info->state.wndExtY);
940
941 if (!IS_WIN9X())
942 EMF_Update_MF_Xform(hdc, info);
943
944 break;
945 }
946 case EMR_SETVIEWPORTORGEX:
947 {
948 const EMRSETVIEWPORTORGEX *pSetViewportOrgEx = (const EMRSETVIEWPORTORGEX *)mr;
949
950 info->state.vportOrgX = pSetViewportOrgEx->ptlOrigin.x;
951 info->state.vportOrgY = pSetViewportOrgEx->ptlOrigin.y;
952 TRACE("SetViewportOrgEx: %d,%d\n", info->state.vportOrgX, info->state.vportOrgY);
953
954 if (!IS_WIN9X())
955 EMF_Update_MF_Xform(hdc, info);
956
957 break;
958 }
959 case EMR_SETVIEWPORTEXTEX:
960 {
961 const EMRSETVIEWPORTEXTEX *pSetViewportExtEx = (const EMRSETVIEWPORTEXTEX *)mr;
962
963 if (info->state.mode != MM_ISOTROPIC && info->state.mode != MM_ANISOTROPIC)
964 break;
965 info->state.vportExtX = pSetViewportExtEx->szlExtent.cx;
966 info->state.vportExtY = pSetViewportExtEx->szlExtent.cy;
967 if (info->state.mode == MM_ISOTROPIC)
968 EMF_FixIsotropic(hdc, info);
969 TRACE("SetViewportExtEx: %d,%d\n", info->state.vportExtX, info->state.vportExtY);
970
971 if (!IS_WIN9X())
972 EMF_Update_MF_Xform(hdc, info);
973
974 break;
975 }
976 case EMR_CREATEPEN:
977 {
978 const EMRCREATEPEN *pCreatePen = (const EMRCREATEPEN *)mr;
979 (handletable->objectHandle)[pCreatePen->ihPen] =
980 CreatePenIndirect(&pCreatePen->lopn);
981 break;
982 }
983 case EMR_EXTCREATEPEN:
984 {
985 const EMREXTCREATEPEN *pPen = (const EMREXTCREATEPEN *)mr;
986 LOGBRUSH lb;
987 lb.lbStyle = pPen->elp.elpBrushStyle;
988 lb.lbColor = pPen->elp.elpColor;
989 lb.lbHatch = pPen->elp.elpHatch;
990
991 if(pPen->offBmi || pPen->offBits)
992 FIXME("EMR_EXTCREATEPEN: Need to copy brush bitmap\n");
993
994 (handletable->objectHandle)[pPen->ihPen] =
995 ExtCreatePen(pPen->elp.elpPenStyle, pPen->elp.elpWidth, &lb,
996 pPen->elp.elpNumEntries, pPen->elp.elpNumEntries ? pPen->elp.elpStyleEntry : NULL);
997 break;
998 }
999 case EMR_CREATEBRUSHINDIRECT:
1000 {
1001 const EMRCREATEBRUSHINDIRECT *pBrush = (const EMRCREATEBRUSHINDIRECT *)mr;
1002 LOGBRUSH brush;
1003 brush.lbStyle = pBrush->lb.lbStyle;
1004 brush.lbColor = pBrush->lb.lbColor;
1005 brush.lbHatch = pBrush->lb.lbHatch;
1006 (handletable->objectHandle)[pBrush->ihBrush] = CreateBrushIndirect(&brush);
1007 break;
1008 }
1009 case EMR_EXTCREATEFONTINDIRECTW:
1010 {
1011 const EMREXTCREATEFONTINDIRECTW *pFont = (const EMREXTCREATEFONTINDIRECTW *)mr;
1012 (handletable->objectHandle)[pFont->ihFont] =
1013 CreateFontIndirectW(&pFont->elfw.elfLogFont);
1014 break;
1015 }
1016 case EMR_MOVETOEX:
1017 {
1018 const EMRMOVETOEX *pMoveToEx = (const EMRMOVETOEX *)mr;
1019 MoveToEx(hdc, pMoveToEx->ptl.x, pMoveToEx->ptl.y, NULL);
1020 break;
1021 }
1022 case EMR_LINETO:
1023 {
1024 const EMRLINETO *pLineTo = (const EMRLINETO *)mr;
1025 LineTo(hdc, pLineTo->ptl.x, pLineTo->ptl.y);
1026 break;
1027 }
1028 case EMR_RECTANGLE:
1029 {
1030 const EMRRECTANGLE *pRect = (const EMRRECTANGLE *)mr;
1031 Rectangle(hdc, pRect->rclBox.left, pRect->rclBox.top,
1032 pRect->rclBox.right, pRect->rclBox.bottom);
1033 break;
1034 }
1035 case EMR_ELLIPSE:
1036 {
1037 const EMRELLIPSE *pEllipse = (const EMRELLIPSE *)mr;
1038 Ellipse(hdc, pEllipse->rclBox.left, pEllipse->rclBox.top,
1039 pEllipse->rclBox.right, pEllipse->rclBox.bottom);
1040 break;
1041 }
1042 case EMR_POLYGON16:
1043 {
1044 const EMRPOLYGON16 *pPoly = (const EMRPOLYGON16 *)mr;
1045 /* Shouldn't use Polygon16 since pPoly->cpts is DWORD */
1046 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
1047 pPoly->cpts * sizeof(POINT) );
1048 DWORD i;
1049 for(i = 0; i < pPoly->cpts; i++)
1050 {
1051 pts[i].x = pPoly->apts[i].x;
1052 pts[i].y = pPoly->apts[i].y;
1053 }
1054 Polygon(hdc, pts, pPoly->cpts);
1055 HeapFree( GetProcessHeap(), 0, pts );
1056 break;
1057 }
1058 case EMR_POLYLINE16:
1059 {
1060 const EMRPOLYLINE16 *pPoly = (const EMRPOLYLINE16 *)mr;
1061 /* Shouldn't use Polyline16 since pPoly->cpts is DWORD */
1062 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
1063 pPoly->cpts * sizeof(POINT) );
1064 DWORD i;
1065 for(i = 0; i < pPoly->cpts; i++)
1066 {
1067 pts[i].x = pPoly->apts[i].x;
1068 pts[i].y = pPoly->apts[i].y;
1069 }
1070 Polyline(hdc, pts, pPoly->cpts);
1071 HeapFree( GetProcessHeap(), 0, pts );
1072 break;
1073 }
1074 case EMR_POLYLINETO16:
1075 {
1076 const EMRPOLYLINETO16 *pPoly = (const EMRPOLYLINETO16 *)mr;
1077 /* Shouldn't use PolylineTo16 since pPoly->cpts is DWORD */
1078 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
1079 pPoly->cpts * sizeof(POINT) );
1080 DWORD i;
1081 for(i = 0; i < pPoly->cpts; i++)
1082 {
1083 pts[i].x = pPoly->apts[i].x;
1084 pts[i].y = pPoly->apts[i].y;
1085 }
1086 PolylineTo(hdc, pts, pPoly->cpts);
1087 HeapFree( GetProcessHeap(), 0, pts );
1088 break;
1089 }
1090 case EMR_POLYBEZIER16:
1091 {
1092 const EMRPOLYBEZIER16 *pPoly = (const EMRPOLYBEZIER16 *)mr;
1093 /* Shouldn't use PolyBezier16 since pPoly->cpts is DWORD */
1094 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
1095 pPoly->cpts * sizeof(POINT) );
1096 DWORD i;
1097 for(i = 0; i < pPoly->cpts; i++)
1098 {
1099 pts[i].x = pPoly->apts[i].x;
1100 pts[i].y = pPoly->apts[i].y;
1101 }
1102 PolyBezier(hdc, pts, pPoly->cpts);
1103 HeapFree( GetProcessHeap(), 0, pts );
1104 break;
1105 }
1106 case EMR_POLYBEZIERTO16:
1107 {
1108 const EMRPOLYBEZIERTO16 *pPoly = (const EMRPOLYBEZIERTO16 *)mr;
1109 /* Shouldn't use PolyBezierTo16 since pPoly->cpts is DWORD */
1110 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
1111 pPoly->cpts * sizeof(POINT) );
1112 DWORD i;
1113 for(i = 0; i < pPoly->cpts; i++)
1114 {
1115 pts[i].x = pPoly->apts[i].x;
1116 pts[i].y = pPoly->apts[i].y;
1117 }
1118 PolyBezierTo(hdc, pts, pPoly->cpts);
1119 HeapFree( GetProcessHeap(), 0, pts );
1120 break;
1121 }
1122 case EMR_POLYPOLYGON16:
1123 {
1124 const EMRPOLYPOLYGON16 *pPolyPoly = (const EMRPOLYPOLYGON16 *)mr;
1125 /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
1126 pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
1127
1128 const POINTS *pts = (const POINTS *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys);
1129 POINT *pt = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) );
1130 DWORD i;
1131 for(i = 0; i < pPolyPoly->cpts; i++)
1132 {
1133 pt[i].x = pts[i].x;
1134 pt[i].y = pts[i].y;
1135 }
1136 PolyPolygon(hdc, pt, (const INT*)pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
1137 HeapFree( GetProcessHeap(), 0, pt );
1138 break;
1139 }
1140 case EMR_POLYPOLYLINE16:
1141 {
1142 const EMRPOLYPOLYLINE16 *pPolyPoly = (const EMRPOLYPOLYLINE16 *)mr;
1143 /* NB POINTS array doesn't start at pPolyPoly->apts it's actually
1144 pPolyPoly->aPolyCounts + pPolyPoly->nPolys */
1145
1146 const POINTS *pts = (const POINTS *)(pPolyPoly->aPolyCounts + pPolyPoly->nPolys);
1147 POINT *pt = HeapAlloc( GetProcessHeap(), 0, pPolyPoly->cpts * sizeof(POINT) );
1148 DWORD i;
1149 for(i = 0; i < pPolyPoly->cpts; i++)
1150 {
1151 pt[i].x = pts[i].x;
1152 pt[i].y = pts[i].y;
1153 }
1154 PolyPolyline(hdc, pt, pPolyPoly->aPolyCounts, pPolyPoly->nPolys);
1155 HeapFree( GetProcessHeap(), 0, pt );
1156 break;
1157 }
1158
1159 case EMR_POLYDRAW16:
1160 {
1161 const EMRPOLYDRAW16 *pPolyDraw16 = (const EMRPOLYDRAW16 *)mr;
1162 const POINTS *ptl = pPolyDraw16->apts;
1163 POINT *pts = HeapAlloc(GetProcessHeap(), 0, pPolyDraw16->cpts * sizeof(POINT));
1164 DWORD i;
1165
1166 /* NB abTypes array doesn't start at pPolyDraw16->abTypes. It's actually
1167 pPolyDraw16->apts + pPolyDraw16->cpts. */
1168 const BYTE *types = (BYTE*)(pPolyDraw16->apts + pPolyDraw16->cpts);
1169
1170 if (!pts)
1171 break;
1172
1173 for (i = 0; i < pPolyDraw16->cpts; ++i)
1174 {
1175 pts[i].x = ptl[i].x;
1176 pts[i].y = ptl[i].y;
1177 }
1178
1179 PolyDraw(hdc, pts, types, pPolyDraw16->cpts);
1180 HeapFree(GetProcessHeap(), 0, pts);
1181 break;
1182 }
1183
1184 case EMR_STRETCHDIBITS:
1185 {
1186 const EMRSTRETCHDIBITS *pStretchDIBits = (const EMRSTRETCHDIBITS *)mr;
1187
1188 StretchDIBits(hdc,
1189 pStretchDIBits->xDest,
1190 pStretchDIBits->yDest,
1191 pStretchDIBits->cxDest,
1192 pStretchDIBits->cyDest,
1193 pStretchDIBits->xSrc,
1194 pStretchDIBits->ySrc,
1195 pStretchDIBits->cxSrc,
1196 pStretchDIBits->cySrc,
1197 (const BYTE *)mr + pStretchDIBits->offBitsSrc,
1198 (const BITMAPINFO *)((const BYTE *)mr + pStretchDIBits->offBmiSrc),
1199 pStretchDIBits->iUsageSrc,
1200 pStretchDIBits->dwRop);
1201 break;
1202 }
1203
1204 case EMR_EXTTEXTOUTA:
1205 {
1206 const EMREXTTEXTOUTA *pExtTextOutA = (const EMREXTTEXTOUTA *)mr;
1207 RECT rc;
1208 const INT *dx = NULL;
1209 int old_mode;
1210
1211 rc.left = pExtTextOutA->emrtext.rcl.left;
1212 rc.top = pExtTextOutA->emrtext.rcl.top;
1213 rc.right = pExtTextOutA->emrtext.rcl.right;
1214 rc.bottom = pExtTextOutA->emrtext.rcl.bottom;
1215 TRACE("EMR_EXTTEXTOUTA: x,y = %d, %d. rect = %s. flags %08x\n",
1216 pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
1217 wine_dbgstr_rect(&rc), pExtTextOutA->emrtext.fOptions);
1218
1219 old_mode = SetGraphicsMode(hdc, pExtTextOutA->iGraphicsMode);
1220 /* Reselect the font back into the dc so that the transformation
1221 gets updated. */
1222 SelectObject(hdc, GetCurrentObject(hdc, OBJ_FONT));
1223
1224 /* Linux version of pstoedit produces EMFs with offDx set to 0.
1225 * These files can be enumerated and played under Win98 just
1226 * fine, but at least Win2k chokes on them.
1227 */
1228 if (pExtTextOutA->emrtext.offDx)
1229 dx = (const INT *)((const BYTE *)mr + pExtTextOutA->emrtext.offDx);
1230
1231 ExtTextOutA(hdc, pExtTextOutA->emrtext.ptlReference.x, pExtTextOutA->emrtext.ptlReference.y,
1232 pExtTextOutA->emrtext.fOptions, &rc,
1233 (LPCSTR)((const BYTE *)mr + pExtTextOutA->emrtext.offString), pExtTextOutA->emrtext.nChars,
1234 dx);
1235
1236 SetGraphicsMode(hdc, old_mode);
1237 break;
1238 }
1239
1240 case EMR_EXTTEXTOUTW:
1241 {
1242 const EMREXTTEXTOUTW *pExtTextOutW = (const EMREXTTEXTOUTW *)mr;
1243 RECT rc;
1244 const INT *dx = NULL;
1245 int old_mode;
1246
1247 rc.left = pExtTextOutW->emrtext.rcl.left;
1248 rc.top = pExtTextOutW->emrtext.rcl.top;
1249 rc.right = pExtTextOutW->emrtext.rcl.right;
1250 rc.bottom = pExtTextOutW->emrtext.rcl.bottom;
1251 TRACE("EMR_EXTTEXTOUTW: x,y = %d, %d. rect = %s. flags %08x\n",
1252 pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
1253 wine_dbgstr_rect(&rc), pExtTextOutW->emrtext.fOptions);
1254
1255 old_mode = SetGraphicsMode(hdc, pExtTextOutW->iGraphicsMode);
1256 /* Reselect the font back into the dc so that the transformation
1257 gets updated. */
1258 SelectObject(hdc, GetCurrentObject(hdc, OBJ_FONT));
1259
1260 /* Linux version of pstoedit produces EMFs with offDx set to 0.
1261 * These files can be enumerated and played under Win98 just
1262 * fine, but at least Win2k chokes on them.
1263 */
1264 if (pExtTextOutW->emrtext.offDx)
1265 dx = (const INT *)((const BYTE *)mr + pExtTextOutW->emrtext.offDx);
1266
1267 ExtTextOutW(hdc, pExtTextOutW->emrtext.ptlReference.x, pExtTextOutW->emrtext.ptlReference.y,
1268 pExtTextOutW->emrtext.fOptions, &rc,
1269 (LPCWSTR)((const BYTE *)mr + pExtTextOutW->emrtext.offString), pExtTextOutW->emrtext.nChars,
1270 dx);
1271
1272 SetGraphicsMode(hdc, old_mode);
1273 break;
1274 }
1275
1276 case EMR_CREATEPALETTE:
1277 {
1278 const EMRCREATEPALETTE *lpCreatePal = (const EMRCREATEPALETTE *)mr;
1279
1280 (handletable->objectHandle)[ lpCreatePal->ihPal ] =
1281 CreatePalette( &lpCreatePal->lgpl );
1282
1283 break;
1284 }
1285
1286 case EMR_SELECTPALETTE:
1287 {
1288 const EMRSELECTPALETTE *lpSelectPal = (const EMRSELECTPALETTE *)mr;
1289
1290 if( lpSelectPal->ihPal & 0x80000000 ) {
1291 SelectPalette( hdc, GetStockObject(lpSelectPal->ihPal & 0x7fffffff), TRUE);
1292 } else {
1293 SelectPalette( hdc, (handletable->objectHandle)[lpSelectPal->ihPal], TRUE);
1294 }
1295 break;
1296 }
1297
1298 case EMR_REALIZEPALETTE:
1299 {
1300 RealizePalette( hdc );
1301 break;
1302 }
1303
1304 case EMR_EXTSELECTCLIPRGN:
1305 {
1306 const EMREXTSELECTCLIPRGN *lpRgn = (const EMREXTSELECTCLIPRGN *)mr;
1307 #ifdef __REACTOS__
1308 const RGNDATA *pRgnData = (const RGNDATA *)lpRgn->RgnData;
1309 DWORD dwSize = sizeof(RGNDATAHEADER) + pRgnData->rdh.nCount * sizeof(RECT);
1310 #endif
1311 HRGN hRgn = 0;
1312
1313 if (mr->nSize >= sizeof(*lpRgn) + sizeof(RGNDATAHEADER))
1314 #ifdef __REACTOS__
1315 hRgn = ExtCreateRegion( &info->init_transform, dwSize, pRgnData );
1316 #else
1317 hRgn = ExtCreateRegion( &info->init_transform, 0, (const RGNDATA *)lpRgn->RgnData );
1318 #endif
1319 ExtSelectClipRgn(hdc, hRgn, (INT)(lpRgn->iMode));
1320 /* ExtSelectClipRgn created a copy of the region */
1321 DeleteObject(hRgn);
1322 break;
1323 }
1324
1325 case EMR_SETMETARGN:
1326 {
1327 SetMetaRgn( hdc );
1328 break;
1329 }
1330
1331 case EMR_SETWORLDTRANSFORM:
1332 {
1333 const EMRSETWORLDTRANSFORM *lpXfrm = (const EMRSETWORLDTRANSFORM *)mr;
1334 info->state.world_transform = lpXfrm->xform;
1335
1336 if (!IS_WIN9X())
1337 EMF_Update_MF_Xform(hdc, info);
1338
1339 break;
1340 }
1341
1342 case EMR_POLYBEZIER:
1343 {
1344 const EMRPOLYBEZIER *lpPolyBez = (const EMRPOLYBEZIER *)mr;
1345 PolyBezier(hdc, (const POINT*)lpPolyBez->aptl, (UINT)lpPolyBez->cptl);
1346 break;
1347 }
1348
1349 case EMR_POLYGON:
1350 {
1351 const EMRPOLYGON *lpPoly = (const EMRPOLYGON *)mr;
1352 Polygon( hdc, (const POINT*)lpPoly->aptl, (UINT)lpPoly->cptl );
1353 break;
1354 }
1355
1356 case EMR_POLYLINE:
1357 {
1358 const EMRPOLYLINE *lpPolyLine = (const EMRPOLYLINE *)mr;
1359 Polyline(hdc, (const POINT*)lpPolyLine->aptl, (UINT)lpPolyLine->cptl);
1360 break;
1361 }
1362
1363 case EMR_POLYBEZIERTO:
1364 {
1365 const EMRPOLYBEZIERTO *lpPolyBezierTo = (const EMRPOLYBEZIERTO *)mr;
1366 PolyBezierTo( hdc, (const POINT*)lpPolyBezierTo->aptl,
1367 (UINT)lpPolyBezierTo->cptl );
1368 break;
1369 }
1370
1371 case EMR_POLYLINETO:
1372 {
1373 const EMRPOLYLINETO *lpPolyLineTo = (const EMRPOLYLINETO *)mr;
1374 PolylineTo( hdc, (const POINT*)lpPolyLineTo->aptl,
1375 (UINT)lpPolyLineTo->cptl );
1376 break;
1377 }
1378
1379 case EMR_POLYPOLYLINE:
1380 {
1381 const EMRPOLYPOLYLINE *pPolyPolyline = (const EMRPOLYPOLYLINE *)mr;
1382 /* NB Points at pPolyPolyline->aPolyCounts + pPolyPolyline->nPolys */
1383
1384 PolyPolyline(hdc, (const POINT*)(pPolyPolyline->aPolyCounts +
1385 pPolyPolyline->nPolys),
1386 pPolyPolyline->aPolyCounts,
1387 pPolyPolyline->nPolys );
1388
1389 break;
1390 }
1391
1392 case EMR_POLYPOLYGON:
1393 {
1394 const EMRPOLYPOLYGON *pPolyPolygon = (const EMRPOLYPOLYGON *)mr;
1395
1396 /* NB Points at pPolyPolygon->aPolyCounts + pPolyPolygon->nPolys */
1397
1398 PolyPolygon(hdc, (const POINT*)(pPolyPolygon->aPolyCounts +
1399 pPolyPolygon->nPolys),
1400 (const INT*)pPolyPolygon->aPolyCounts, pPolyPolygon->nPolys );
1401 break;
1402 }
1403
1404 case EMR_SETBRUSHORGEX:
1405 {
1406 const EMRSETBRUSHORGEX *lpSetBrushOrgEx = (const EMRSETBRUSHORGEX *)mr;
1407
1408 SetBrushOrgEx( hdc,
1409 (INT)lpSetBrushOrgEx->ptlOrigin.x,
1410 (INT)lpSetBrushOrgEx->ptlOrigin.y,
1411 NULL );
1412
1413 break;
1414 }
1415
1416 case EMR_SETPIXELV:
1417 {
1418 const EMRSETPIXELV *lpSetPixelV = (const EMRSETPIXELV *)mr;
1419
1420 SetPixelV( hdc,
1421 (INT)lpSetPixelV->ptlPixel.x,
1422 (INT)lpSetPixelV->ptlPixel.y,
1423 lpSetPixelV->crColor );
1424
1425 break;
1426 }
1427
1428 case EMR_SETMAPPERFLAGS:
1429 {
1430 const EMRSETMAPPERFLAGS *lpSetMapperFlags = (const EMRSETMAPPERFLAGS *)mr;
1431
1432 SetMapperFlags( hdc, lpSetMapperFlags->dwFlags );
1433
1434 break;
1435 }
1436
1437 case EMR_SETCOLORADJUSTMENT:
1438 {
1439 const EMRSETCOLORADJUSTMENT *lpSetColorAdjust = (const EMRSETCOLORADJUSTMENT *)mr;
1440
1441 SetColorAdjustment( hdc, &lpSetColorAdjust->ColorAdjustment );
1442
1443 break;
1444 }
1445
1446 case EMR_OFFSETCLIPRGN:
1447 {
1448 const EMROFFSETCLIPRGN *lpOffsetClipRgn = (const EMROFFSETCLIPRGN *)mr;
1449
1450 OffsetClipRgn( hdc,
1451 (INT)lpOffsetClipRgn->ptlOffset.x,
1452 (INT)lpOffsetClipRgn->ptlOffset.y );
1453 FIXME("OffsetClipRgn\n");
1454
1455 break;
1456 }
1457
1458 case EMR_EXCLUDECLIPRECT:
1459 {
1460 const EMREXCLUDECLIPRECT *lpExcludeClipRect = (const EMREXCLUDECLIPRECT *)mr;
1461
1462 ExcludeClipRect( hdc,
1463 lpExcludeClipRect->rclClip.left,
1464 lpExcludeClipRect->rclClip.top,
1465 lpExcludeClipRect->rclClip.right,
1466 lpExcludeClipRect->rclClip.bottom );
1467 FIXME("ExcludeClipRect\n");
1468
1469 break;
1470 }
1471
1472 case EMR_SCALEVIEWPORTEXTEX:
1473 {
1474 const EMRSCALEVIEWPORTEXTEX *lpScaleViewportExtEx = (const EMRSCALEVIEWPORTEXTEX *)mr;
1475
1476 if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
1477 break;
1478 if (!lpScaleViewportExtEx->xNum || !lpScaleViewportExtEx->xDenom ||
1479 !lpScaleViewportExtEx->yNum || !lpScaleViewportExtEx->yDenom)
1480 break;
1481 info->state.vportExtX = MulDiv(info->state.vportExtX, lpScaleViewportExtEx->xNum,
1482 lpScaleViewportExtEx->xDenom);
1483 info->state.vportExtY = MulDiv(info->state.vportExtY, lpScaleViewportExtEx->yNum,
1484 lpScaleViewportExtEx->yDenom);
1485 if (info->state.vportExtX == 0) info->state.vportExtX = 1;
1486 if (info->state.vportExtY == 0) info->state.vportExtY = 1;
1487 if (info->state.mode == MM_ISOTROPIC)
1488 EMF_FixIsotropic(hdc, info);
1489
1490 TRACE("EMRSCALEVIEWPORTEXTEX %d/%d %d/%d\n",
1491 lpScaleViewportExtEx->xNum,lpScaleViewportExtEx->xDenom,
1492 lpScaleViewportExtEx->yNum,lpScaleViewportExtEx->yDenom);
1493
1494 if (!IS_WIN9X())
1495 EMF_Update_MF_Xform(hdc, info);
1496
1497 break;
1498 }
1499
1500 case EMR_SCALEWINDOWEXTEX:
1501 {
1502 const EMRSCALEWINDOWEXTEX *lpScaleWindowExtEx = (const EMRSCALEWINDOWEXTEX *)mr;
1503
1504 if ((info->state.mode != MM_ISOTROPIC) && (info->state.mode != MM_ANISOTROPIC))
1505 break;
1506 if (!lpScaleWindowExtEx->xNum || !lpScaleWindowExtEx->xDenom ||
1507 !lpScaleWindowExtEx->yNum || !lpScaleWindowExtEx->yDenom)
1508 break;
1509 info->state.wndExtX = MulDiv(info->state.wndExtX, lpScaleWindowExtEx->xNum,
1510 lpScaleWindowExtEx->xDenom);
1511 info->state.wndExtY = MulDiv(info->state.wndExtY, lpScaleWindowExtEx->yNum,
1512 lpScaleWindowExtEx->yDenom);
1513 if (info->state.wndExtX == 0) info->state.wndExtX = 1;
1514 if (info->state.wndExtY == 0) info->state.wndExtY = 1;
1515 if (info->state.mode == MM_ISOTROPIC)
1516 EMF_FixIsotropic(hdc, info);
1517
1518 TRACE("EMRSCALEWINDOWEXTEX %d/%d %d/%d\n",
1519 lpScaleWindowExtEx->xNum,lpScaleWindowExtEx->xDenom,
1520 lpScaleWindowExtEx->yNum,lpScaleWindowExtEx->yDenom);
1521
1522 if (!IS_WIN9X())
1523 EMF_Update_MF_Xform(hdc, info);
1524
1525 break;
1526 }
1527
1528 case EMR_MODIFYWORLDTRANSFORM:
1529 {
1530 const EMRMODIFYWORLDTRANSFORM *lpModifyWorldTrans = (const EMRMODIFYWORLDTRANSFORM *)mr;
1531
1532 switch(lpModifyWorldTrans->iMode) {
1533 case MWT_IDENTITY:
1534 info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
1535 info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
1536 info->state.world_transform.eDx = info->state.world_transform.eDy = 0;
1537 if (!IS_WIN9X())
1538 EMF_Update_MF_Xform(hdc, info);
1539 break;
1540 case MWT_LEFTMULTIPLY:
1541 CombineTransform(&info->state.world_transform, &lpModifyWorldTrans->xform,
1542 &info->state.world_transform);
1543 if (!IS_WIN9X())
1544 ModifyWorldTransform(hdc, &lpModifyWorldTrans->xform, MWT_LEFTMULTIPLY);
1545 break;
1546 case MWT_RIGHTMULTIPLY:
1547 CombineTransform(&info->state.world_transform, &info->state.world_transform,
1548 &lpModifyWorldTrans->xform);
1549 if (!IS_WIN9X())
1550 EMF_Update_MF_Xform(hdc, info);
1551 break;
1552 default:
1553 FIXME("Unknown imode %d\n", lpModifyWorldTrans->iMode);
1554 break;
1555 }
1556 break;
1557 }
1558
1559 case EMR_ANGLEARC:
1560 {
1561 const EMRANGLEARC *lpAngleArc = (const EMRANGLEARC *)mr;
1562
1563 AngleArc( hdc,
1564 (INT)lpAngleArc->ptlCenter.x, (INT)lpAngleArc->ptlCenter.y,
1565 lpAngleArc->nRadius, lpAngleArc->eStartAngle,
1566 lpAngleArc->eSweepAngle );
1567
1568 break;
1569 }
1570
1571 case EMR_ROUNDRECT:
1572 {
1573 const EMRROUNDRECT *lpRoundRect = (const EMRROUNDRECT *)mr;
1574
1575 RoundRect( hdc,
1576 lpRoundRect->rclBox.left,
1577 lpRoundRect->rclBox.top,
1578 lpRoundRect->rclBox.right,
1579 lpRoundRect->rclBox.bottom,
1580 lpRoundRect->szlCorner.cx,
1581 lpRoundRect->szlCorner.cy );
1582
1583 break;
1584 }
1585
1586 case EMR_ARC:
1587 {
1588 const EMRARC *lpArc = (const EMRARC *)mr;
1589
1590 Arc( hdc,
1591 (INT)lpArc->rclBox.left,
1592 (INT)lpArc->rclBox.top,
1593 (INT)lpArc->rclBox.right,
1594 (INT)lpArc->rclBox.bottom,
1595 (INT)lpArc->ptlStart.x,
1596 (INT)lpArc->ptlStart.y,
1597 (INT)lpArc->ptlEnd.x,
1598 (INT)lpArc->ptlEnd.y );
1599
1600 break;
1601 }
1602
1603 case EMR_CHORD:
1604 {
1605 const EMRCHORD *lpChord = (const EMRCHORD *)mr;
1606
1607 Chord( hdc,
1608 (INT)lpChord->rclBox.left,
1609 (INT)lpChord->rclBox.top,
1610 (INT)lpChord->rclBox.right,
1611 (INT)lpChord->rclBox.bottom,
1612 (INT)lpChord->ptlStart.x,
1613 (INT)lpChord->ptlStart.y,
1614 (INT)lpChord->ptlEnd.x,
1615 (INT)lpChord->ptlEnd.y );
1616
1617 break;
1618 }
1619
1620 case EMR_PIE:
1621 {
1622 const EMRPIE *lpPie = (const EMRPIE *)mr;
1623
1624 Pie( hdc,
1625 (INT)lpPie->rclBox.left,
1626 (INT)lpPie->rclBox.top,
1627 (INT)lpPie->rclBox.right,
1628 (INT)lpPie->rclBox.bottom,
1629 (INT)lpPie->ptlStart.x,
1630 (INT)lpPie->ptlStart.y,
1631 (INT)lpPie->ptlEnd.x,
1632 (INT)lpPie->ptlEnd.y );
1633
1634 break;
1635 }
1636
1637 case EMR_ARCTO:
1638 {
1639 const EMRARC *lpArcTo = (const EMRARC *)mr;
1640
1641 ArcTo( hdc,
1642 (INT)lpArcTo->rclBox.left,
1643 (INT)lpArcTo->rclBox.top,
1644 (INT)lpArcTo->rclBox.right,
1645 (INT)lpArcTo->rclBox.bottom,
1646 (INT)lpArcTo->ptlStart.x,
1647 (INT)lpArcTo->ptlStart.y,
1648 (INT)lpArcTo->ptlEnd.x,
1649 (INT)lpArcTo->ptlEnd.y );
1650
1651 break;
1652 }
1653
1654 case EMR_EXTFLOODFILL:
1655 {
1656 const EMREXTFLOODFILL *lpExtFloodFill = (const EMREXTFLOODFILL *)mr;
1657
1658 ExtFloodFill( hdc,
1659 (INT)lpExtFloodFill->ptlStart.x,
1660 (INT)lpExtFloodFill->ptlStart.y,
1661 lpExtFloodFill->crColor,
1662 (UINT)lpExtFloodFill->iMode );
1663
1664 break;
1665 }
1666
1667 case EMR_POLYDRAW:
1668 {
1669 const EMRPOLYDRAW *lpPolyDraw = (const EMRPOLYDRAW *)mr;
1670 PolyDraw( hdc,
1671 (const POINT*)lpPolyDraw->aptl,
1672 lpPolyDraw->abTypes,
1673 (INT)lpPolyDraw->cptl );
1674
1675 break;
1676 }
1677
1678 case EMR_SETARCDIRECTION:
1679 {
1680 const EMRSETARCDIRECTION *lpSetArcDirection = (const EMRSETARCDIRECTION *)mr;
1681 SetArcDirection( hdc, (INT)lpSetArcDirection->iArcDirection );
1682 break;
1683 }
1684
1685 case EMR_SETMITERLIMIT:
1686 {
1687 const EMRSETMITERLIMIT *lpSetMiterLimit = (const EMRSETMITERLIMIT *)mr;
1688 SetMiterLimit( hdc, lpSetMiterLimit->eMiterLimit, NULL );
1689 break;
1690 }
1691
1692 case EMR_BEGINPATH:
1693 {
1694 BeginPath( hdc );
1695 break;
1696 }
1697
1698 case EMR_ENDPATH:
1699 {
1700 EndPath( hdc );
1701 break;
1702 }
1703
1704 case EMR_CLOSEFIGURE:
1705 {
1706 CloseFigure( hdc );
1707 break;
1708 }
1709
1710 case EMR_FILLPATH:
1711 {
1712 /*const EMRFILLPATH lpFillPath = (const EMRFILLPATH *)mr;*/
1713 FillPath( hdc );
1714 break;
1715 }
1716
1717 case EMR_STROKEANDFILLPATH:
1718 {
1719 /*const EMRSTROKEANDFILLPATH lpStrokeAndFillPath = (const EMRSTROKEANDFILLPATH *)mr;*/
1720 StrokeAndFillPath( hdc );
1721 break;
1722 }
1723
1724 case EMR_STROKEPATH:
1725 {
1726 /*const EMRSTROKEPATH lpStrokePath = (const EMRSTROKEPATH *)mr;*/
1727 StrokePath( hdc );
1728 break;
1729 }
1730
1731 case EMR_FLATTENPATH:
1732 {
1733 FlattenPath( hdc );
1734 break;
1735 }
1736
1737 case EMR_WIDENPATH:
1738 {
1739 WidenPath( hdc );
1740 break;
1741 }
1742
1743 case EMR_SELECTCLIPPATH:
1744 {
1745 const EMRSELECTCLIPPATH *lpSelectClipPath = (const EMRSELECTCLIPPATH *)mr;
1746 SelectClipPath( hdc, (INT)lpSelectClipPath->iMode );
1747 break;
1748 }
1749
1750 case EMR_ABORTPATH:
1751 {
1752 AbortPath( hdc );
1753 break;
1754 }
1755
1756 case EMR_CREATECOLORSPACE:
1757 {
1758 PEMRCREATECOLORSPACE lpCreateColorSpace = (PEMRCREATECOLORSPACE)mr;
1759 (handletable->objectHandle)[lpCreateColorSpace->ihCS] =
1760 CreateColorSpaceA( &lpCreateColorSpace->lcs );
1761 break;
1762 }
1763
1764 case EMR_SETCOLORSPACE:
1765 {
1766 const EMRSETCOLORSPACE *lpSetColorSpace = (const EMRSETCOLORSPACE *)mr;
1767 SetColorSpace( hdc,
1768 (handletable->objectHandle)[lpSetColorSpace->ihCS] );
1769 break;
1770 }
1771
1772 case EMR_DELETECOLORSPACE:
1773 {
1774 const EMRDELETECOLORSPACE *lpDeleteColorSpace = (const EMRDELETECOLORSPACE *)mr;
1775 DeleteColorSpace( (handletable->objectHandle)[lpDeleteColorSpace->ihCS] );
1776 break;
1777 }
1778
1779 case EMR_SETICMMODE:
1780 {
1781 const EMRSETICMMODE *lpSetICMMode = (const EMRSETICMMODE *)mr;
1782 SetICMMode( hdc, (INT)lpSetICMMode->iMode );
1783 break;
1784 }
1785
1786 case EMR_PIXELFORMAT:
1787 {
1788 INT iPixelFormat;
1789 const EMRPIXELFORMAT *lpPixelFormat = (const EMRPIXELFORMAT *)mr;
1790
1791 iPixelFormat = ChoosePixelFormat( hdc, &lpPixelFormat->pfd );
1792 SetPixelFormat( hdc, iPixelFormat, &lpPixelFormat->pfd );
1793
1794 break;
1795 }
1796
1797 case EMR_SETPALETTEENTRIES:
1798 {
1799 const EMRSETPALETTEENTRIES *lpSetPaletteEntries = (const EMRSETPALETTEENTRIES *)mr;
1800
1801 SetPaletteEntries( (handletable->objectHandle)[lpSetPaletteEntries->ihPal],
1802 (UINT)lpSetPaletteEntries->iStart,
1803 (UINT)lpSetPaletteEntries->cEntries,
1804 lpSetPaletteEntries->aPalEntries );
1805
1806 break;
1807 }
1808
1809 case EMR_RESIZEPALETTE:
1810 {
1811 const EMRRESIZEPALETTE *lpResizePalette = (const EMRRESIZEPALETTE *)mr;
1812
1813 ResizePalette( (handletable->objectHandle)[lpResizePalette->ihPal],
1814 (UINT)lpResizePalette->cEntries );
1815
1816 break;
1817 }
1818
1819 case EMR_CREATEDIBPATTERNBRUSHPT:
1820 {
1821 const EMRCREATEDIBPATTERNBRUSHPT *lpCreate = (const EMRCREATEDIBPATTERNBRUSHPT *)mr;
1822 LPVOID lpPackedStruct;
1823
1824 /* Check that offsets and data are contained within the record
1825 * (including checking for wrap-arounds).
1826 */
1827 if ( lpCreate->offBmi + lpCreate->cbBmi > mr->nSize
1828 || lpCreate->offBits + lpCreate->cbBits > mr->nSize
1829 || lpCreate->offBmi + lpCreate->cbBmi < lpCreate->offBmi
1830 || lpCreate->offBits + lpCreate->cbBits < lpCreate->offBits )
1831 {
1832 ERR("Invalid EMR_CREATEDIBPATTERNBRUSHPT record\n");
1833 break;
1834 }
1835
1836 /* This is a BITMAPINFO struct followed directly by bitmap bits */
1837 lpPackedStruct = HeapAlloc( GetProcessHeap(), 0,
1838 lpCreate->cbBmi + lpCreate->cbBits );
1839 if(!lpPackedStruct)
1840 {
1841 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1842 break;
1843 }
1844
1845 /* Now pack this structure */
1846 memcpy( lpPackedStruct,
1847 ((const BYTE *)lpCreate) + lpCreate->offBmi,
1848 lpCreate->cbBmi );
1849 memcpy( ((BYTE*)lpPackedStruct) + lpCreate->cbBmi,
1850 ((const BYTE *)lpCreate) + lpCreate->offBits,
1851 lpCreate->cbBits );
1852
1853 (handletable->objectHandle)[lpCreate->ihBrush] =
1854 CreateDIBPatternBrushPt( lpPackedStruct,
1855 (UINT)lpCreate->iUsage );
1856
1857 HeapFree(GetProcessHeap(), 0, lpPackedStruct);
1858 break;
1859 }
1860
1861 case EMR_CREATEMONOBRUSH:
1862 {
1863 const EMRCREATEMONOBRUSH *pCreateMonoBrush = (const EMRCREATEMONOBRUSH *)mr;
1864 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pCreateMonoBrush->offBmi);
1865 HBITMAP hBmp;
1866
1867 /* Need to check if the bitmap is monochrome, and if the
1868 two colors are really black and white */
1869 if (pCreateMonoBrush->iUsage == DIB_PAL_MONO)
1870 {
1871 BITMAP bm;
1872
1873 /* Undocumented iUsage indicates a mono bitmap with no palette table,
1874 * aligned to 32 rather than 16 bits.
1875 */
1876 bm.bmType = 0;
1877 bm.bmWidth = pbi->bmiHeader.biWidth;
1878 bm.bmHeight = abs(pbi->bmiHeader.biHeight);
1879 bm.bmWidthBytes = 4 * ((pbi->bmiHeader.biWidth + 31) / 32);
1880 bm.bmPlanes = pbi->bmiHeader.biPlanes;
1881 bm.bmBitsPixel = pbi->bmiHeader.biBitCount;
1882 bm.bmBits = (BYTE *)mr + pCreateMonoBrush->offBits;
1883 hBmp = CreateBitmapIndirect(&bm);
1884 }
1885 else if (is_dib_monochrome(pbi))
1886 {
1887 /* Top-down DIBs have a negative height */
1888 LONG height = pbi->bmiHeader.biHeight;
1889
1890 hBmp = CreateBitmap(pbi->bmiHeader.biWidth, abs(height), 1, 1, NULL);
1891 SetDIBits(hdc, hBmp, 0, pbi->bmiHeader.biHeight,
1892 (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1893 }
1894 else
1895 {
1896 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
1897 (const BYTE *)mr + pCreateMonoBrush->offBits, pbi, pCreateMonoBrush->iUsage);
1898 }
1899
1900 (handletable->objectHandle)[pCreateMonoBrush->ihBrush] = CreatePatternBrush(hBmp);
1901
1902 /* CreatePatternBrush created a copy of the bitmap */
1903 DeleteObject(hBmp);
1904 break;
1905 }
1906
1907 case EMR_BITBLT:
1908 {
1909 const EMRBITBLT *pBitBlt = (const EMRBITBLT *)mr;
1910
1911 if(pBitBlt->offBmiSrc == 0) { /* Record is a PatBlt */
1912 PatBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest,
1913 pBitBlt->dwRop);
1914 } else { /* BitBlt */
1915 HDC hdcSrc = CreateCompatibleDC(hdc);
1916 HBRUSH hBrush, hBrushOld;
1917 HBITMAP hBmp = 0, hBmpOld = 0;
1918 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pBitBlt->offBmiSrc);
1919
1920 SetGraphicsMode(hdcSrc, GM_ADVANCED);
1921 SetWorldTransform(hdcSrc, &pBitBlt->xformSrc);
1922
1923 hBrush = CreateSolidBrush(pBitBlt->crBkColorSrc);
1924 hBrushOld = SelectObject(hdcSrc, hBrush);
1925 PatBlt(hdcSrc, pBitBlt->rclBounds.left, pBitBlt->rclBounds.top,
1926 pBitBlt->rclBounds.right - pBitBlt->rclBounds.left,
1927 pBitBlt->rclBounds.bottom - pBitBlt->rclBounds.top, PATCOPY);
1928 SelectObject(hdcSrc, hBrushOld);
1929 DeleteObject(hBrush);
1930
1931 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
1932 (const BYTE *)mr + pBitBlt->offBitsSrc, pbi, pBitBlt->iUsageSrc);
1933 hBmpOld = SelectObject(hdcSrc, hBmp);
1934
1935 BitBlt(hdc, pBitBlt->xDest, pBitBlt->yDest, pBitBlt->cxDest, pBitBlt->cyDest,
1936 hdcSrc, pBitBlt->xSrc, pBitBlt->ySrc, pBitBlt->dwRop);
1937
1938 SelectObject(hdcSrc, hBmpOld);
1939 DeleteObject(hBmp);
1940 DeleteDC(hdcSrc);
1941 }
1942 break;
1943 }
1944
1945 case EMR_STRETCHBLT:
1946 {
1947 const EMRSTRETCHBLT *pStretchBlt = (const EMRSTRETCHBLT *)mr;
1948
1949 TRACE("EMR_STRETCHBLT: %d, %d %dx%d -> %d, %d %dx%d. rop %08x offBitsSrc %d\n",
1950 pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc,
1951 pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
1952 pStretchBlt->dwRop, pStretchBlt->offBitsSrc);
1953
1954 if(pStretchBlt->offBmiSrc == 0) { /* Record is a PatBlt */
1955 PatBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
1956 pStretchBlt->dwRop);
1957 } else { /* StretchBlt */
1958 HDC hdcSrc = CreateCompatibleDC(hdc);
1959 HBRUSH hBrush, hBrushOld;
1960 HBITMAP hBmp = 0, hBmpOld = 0;
1961 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pStretchBlt->offBmiSrc);
1962
1963 SetGraphicsMode(hdcSrc, GM_ADVANCED);
1964 SetWorldTransform(hdcSrc, &pStretchBlt->xformSrc);
1965
1966 hBrush = CreateSolidBrush(pStretchBlt->crBkColorSrc);
1967 hBrushOld = SelectObject(hdcSrc, hBrush);
1968 PatBlt(hdcSrc, pStretchBlt->rclBounds.left, pStretchBlt->rclBounds.top,
1969 pStretchBlt->rclBounds.right - pStretchBlt->rclBounds.left,
1970 pStretchBlt->rclBounds.bottom - pStretchBlt->rclBounds.top, PATCOPY);
1971 SelectObject(hdcSrc, hBrushOld);
1972 DeleteObject(hBrush);
1973
1974 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
1975 (const BYTE *)mr + pStretchBlt->offBitsSrc, pbi, pStretchBlt->iUsageSrc);
1976 hBmpOld = SelectObject(hdcSrc, hBmp);
1977
1978 StretchBlt(hdc, pStretchBlt->xDest, pStretchBlt->yDest, pStretchBlt->cxDest, pStretchBlt->cyDest,
1979 hdcSrc, pStretchBlt->xSrc, pStretchBlt->ySrc, pStretchBlt->cxSrc, pStretchBlt->cySrc,
1980 pStretchBlt->dwRop);
1981
1982 SelectObject(hdcSrc, hBmpOld);
1983 DeleteObject(hBmp);
1984 DeleteDC(hdcSrc);
1985 }
1986 break;
1987 }
1988
1989 case EMR_ALPHABLEND:
1990 {
1991 const EMRALPHABLEND *pAlphaBlend = (const EMRALPHABLEND *)mr;
1992
1993 TRACE("EMR_ALPHABLEND: %d, %d %dx%d -> %d, %d %dx%d. blendfn %08x offBitsSrc %d\n",
1994 pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc,
1995 pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest,
1996 pAlphaBlend->dwRop, pAlphaBlend->offBitsSrc);
1997
1998 if(pAlphaBlend->offBmiSrc == 0) {
1999 FIXME("EMR_ALPHABLEND: offBmiSrc == 0\n");
2000 } else {
2001 HDC hdcSrc = CreateCompatibleDC(hdc);
2002 HBITMAP hBmp = 0, hBmpOld = 0;
2003 const BITMAPINFO *pbi = (const BITMAPINFO *)((const BYTE *)mr + pAlphaBlend->offBmiSrc);
2004 void *bits;
2005
2006 SetGraphicsMode(hdcSrc, GM_ADVANCED);
2007 SetWorldTransform(hdcSrc, &pAlphaBlend->xformSrc);
2008
2009 hBmp = CreateDIBSection(hdc, pbi, pAlphaBlend->iUsageSrc, &bits, NULL, 0);
2010 memcpy(bits, (const BYTE *)mr + pAlphaBlend->offBitsSrc, pAlphaBlend->cbBitsSrc);
2011 hBmpOld = SelectObject(hdcSrc, hBmp);
2012
2013 GdiAlphaBlend(hdc, pAlphaBlend->xDest, pAlphaBlend->yDest, pAlphaBlend->cxDest, pAlphaBlend->cyDest,
2014 hdcSrc, pAlphaBlend->xSrc, pAlphaBlend->ySrc, pAlphaBlend->cxSrc, pAlphaBlend->cySrc,
2015 *(BLENDFUNCTION *)&pAlphaBlend->dwRop);
2016
2017 SelectObject(hdcSrc, hBmpOld);
2018 DeleteObject(hBmp);
2019 DeleteDC(hdcSrc);
2020 }
2021 break;
2022 }
2023
2024 case EMR_MASKBLT:
2025 {
2026 const EMRMASKBLT *pMaskBlt = (const EMRMASKBLT *)mr;
2027 HDC hdcSrc = CreateCompatibleDC(hdc);
2028 HBRUSH hBrush, hBrushOld;
2029 HBITMAP hBmp, hBmpOld, hBmpMask;
2030 const BITMAPINFO *pbi;
2031
2032 SetGraphicsMode(hdcSrc, GM_ADVANCED);
2033 SetWorldTransform(hdcSrc, &pMaskBlt->xformSrc);
2034
2035 hBrush = CreateSolidBrush(pMaskBlt->crBkColorSrc);
2036 hBrushOld = SelectObject(hdcSrc, hBrush);
2037 PatBlt(hdcSrc, pMaskBlt->rclBounds.left, pMaskBlt->rclBounds.top,
2038 pMaskBlt->rclBounds.right - pMaskBlt->rclBounds.left,
2039 pMaskBlt->rclBounds.bottom - pMaskBlt->rclBounds.top, PATCOPY);
2040 SelectObject(hdcSrc, hBrushOld);
2041 DeleteObject(hBrush);
2042
2043 pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiMask);
2044 hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight,
2045 1, 1, NULL);
2046 SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight,
2047 (const BYTE *)mr + pMaskBlt->offBitsMask, pbi, pMaskBlt->iUsageMask);
2048
2049 pbi = (const BITMAPINFO *)((const BYTE *)mr + pMaskBlt->offBmiSrc);
2050 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
2051 (const BYTE *)mr + pMaskBlt->offBitsSrc, pbi, pMaskBlt->iUsageSrc);
2052 hBmpOld = SelectObject(hdcSrc, hBmp);
2053 MaskBlt(hdc,
2054 pMaskBlt->xDest,
2055 pMaskBlt->yDest,
2056 pMaskBlt->cxDest,
2057 pMaskBlt->cyDest,
2058 hdcSrc,
2059 pMaskBlt->xSrc,
2060 pMaskBlt->ySrc,
2061 hBmpMask,
2062 pMaskBlt->xMask,
2063 pMaskBlt->yMask,
2064 pMaskBlt->dwRop);
2065 SelectObject(hdcSrc, hBmpOld);
2066 DeleteObject(hBmp);
2067 DeleteObject(hBmpMask);
2068 DeleteDC(hdcSrc);
2069 break;
2070 }
2071
2072 case EMR_PLGBLT:
2073 {
2074 const EMRPLGBLT *pPlgBlt = (const EMRPLGBLT *)mr;
2075 HDC hdcSrc = CreateCompatibleDC(hdc);
2076 HBRUSH hBrush, hBrushOld;
2077 HBITMAP hBmp, hBmpOld, hBmpMask;
2078 const BITMAPINFO *pbi;
2079 POINT pts[3];
2080
2081 SetGraphicsMode(hdcSrc, GM_ADVANCED);
2082 SetWorldTransform(hdcSrc, &pPlgBlt->xformSrc);
2083
2084 pts[0].x = pPlgBlt->aptlDest[0].x; pts[0].y = pPlgBlt->aptlDest[0].y;
2085 pts[1].x = pPlgBlt->aptlDest[1].x; pts[1].y = pPlgBlt->aptlDest[1].y;
2086 pts[2].x = pPlgBlt->aptlDest[2].x; pts[2].y = pPlgBlt->aptlDest[2].y;
2087
2088 hBrush = CreateSolidBrush(pPlgBlt->crBkColorSrc);
2089 hBrushOld = SelectObject(hdcSrc, hBrush);
2090 PatBlt(hdcSrc, pPlgBlt->rclBounds.left, pPlgBlt->rclBounds.top,
2091 pPlgBlt->rclBounds.right - pPlgBlt->rclBounds.left,
2092 pPlgBlt->rclBounds.bottom - pPlgBlt->rclBounds.top, PATCOPY);
2093 SelectObject(hdcSrc, hBrushOld);
2094 DeleteObject(hBrush);
2095
2096 pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiMask);
2097 hBmpMask = CreateBitmap(pbi->bmiHeader.biWidth, pbi->bmiHeader.biHeight,
2098 1, 1, NULL);
2099 SetDIBits(hdc, hBmpMask, 0, pbi->bmiHeader.biHeight,
2100 (const BYTE *)mr + pPlgBlt->offBitsMask, pbi, pPlgBlt->iUsageMask);
2101
2102 pbi = (const BITMAPINFO *)((const BYTE *)mr + pPlgBlt->offBmiSrc);
2103 hBmp = CreateDIBitmap(hdc, (const BITMAPINFOHEADER *)pbi, CBM_INIT,
2104 (const BYTE *)mr + pPlgBlt->offBitsSrc, pbi, pPlgBlt->iUsageSrc);
2105 hBmpOld = SelectObject(hdcSrc, hBmp);
2106 PlgBlt(hdc,
2107 pts,
2108 hdcSrc,
2109 pPlgBlt->xSrc,
2110 pPlgBlt->ySrc,
2111 pPlgBlt->cxSrc,
2112 pPlgBlt->cySrc,
2113 hBmpMask,
2114 pPlgBlt->xMask,
2115 pPlgBlt->yMask);
2116 SelectObject(hdcSrc, hBmpOld);
2117 DeleteObject(hBmp);
2118 DeleteObject(hBmpMask);
2119 DeleteDC(hdcSrc);
2120 break;
2121 }
2122
2123 case EMR_SETDIBITSTODEVICE:
2124 {
2125 const EMRSETDIBITSTODEVICE *pSetDIBitsToDevice = (const EMRSETDIBITSTODEVICE *)mr;
2126
2127 SetDIBitsToDevice(hdc,
2128 pSetDIBitsToDevice->xDest,
2129 pSetDIBitsToDevice->yDest,
2130 pSetDIBitsToDevice->cxSrc,
2131 pSetDIBitsToDevice->cySrc,
2132 pSetDIBitsToDevice->xSrc,
2133 pSetDIBitsToDevice->ySrc,
2134 pSetDIBitsToDevice->iStartScan,
2135 pSetDIBitsToDevice->cScans,
2136 (const BYTE *)mr + pSetDIBitsToDevice->offBitsSrc,
2137 (const BITMAPINFO *)((const BYTE *)mr + pSetDIBitsToDevice->offBmiSrc),
2138 pSetDIBitsToDevice->iUsageSrc);
2139 break;
2140 }
2141
2142 case EMR_POLYTEXTOUTA:
2143 {
2144 const EMRPOLYTEXTOUTA *pPolyTextOutA = (const EMRPOLYTEXTOUTA *)mr;
2145 POLYTEXTA *polytextA = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutA->cStrings * sizeof(POLYTEXTA));
2146 LONG i;
2147 XFORM xform, xformOld;
2148 int gModeOld;
2149
2150 gModeOld = SetGraphicsMode(hdc, pPolyTextOutA->iGraphicsMode);
2151 GetWorldTransform(hdc, &xformOld);
2152
2153 xform.eM11 = pPolyTextOutA->exScale;
2154 xform.eM12 = 0.0;
2155 xform.eM21 = 0.0;
2156 xform.eM22 = pPolyTextOutA->eyScale;
2157 xform.eDx = 0.0;
2158 xform.eDy = 0.0;
2159 SetWorldTransform(hdc, &xform);
2160
2161 /* Set up POLYTEXTA structures */
2162 for(i = 0; i < pPolyTextOutA->cStrings; i++)
2163 {
2164 polytextA[i].x = pPolyTextOutA->aemrtext[i].ptlReference.x;
2165 polytextA[i].y = pPolyTextOutA->aemrtext[i].ptlReference.y;
2166 polytextA[i].n = pPolyTextOutA->aemrtext[i].nChars;
2167 polytextA[i].lpstr = (LPCSTR)((const BYTE *)mr + pPolyTextOutA->aemrtext[i].offString);
2168 polytextA[i].uiFlags = pPolyTextOutA->aemrtext[i].fOptions;
2169 polytextA[i].rcl.left = pPolyTextOutA->aemrtext[i].rcl.left;
2170 polytextA[i].rcl.right = pPolyTextOutA->aemrtext[i].rcl.right;
2171 polytextA[i].rcl.top = pPolyTextOutA->aemrtext[i].rcl.top;
2172 polytextA[i].rcl.bottom = pPolyTextOutA->aemrtext[i].rcl.bottom;
2173 polytextA[i].pdx = (int *)((BYTE *)mr + pPolyTextOutA->aemrtext[i].offDx);
2174 }
2175 PolyTextOutA(hdc, polytextA, pPolyTextOutA->cStrings);
2176 HeapFree(GetProcessHeap(), 0, polytextA);
2177
2178 SetWorldTransform(hdc, &xformOld);
2179 SetGraphicsMode(hdc, gModeOld);
2180 break;
2181 }
2182
2183 case EMR_POLYTEXTOUTW:
2184 {
2185 const EMRPOLYTEXTOUTW *pPolyTextOutW = (const EMRPOLYTEXTOUTW *)mr;
2186 POLYTEXTW *polytextW = HeapAlloc(GetProcessHeap(), 0, pPolyTextOutW->cStrings * sizeof(POLYTEXTW));
2187 LONG i;
2188 XFORM xform, xformOld;
2189 int gModeOld;
2190
2191 gModeOld = SetGraphicsMode(hdc, pPolyTextOutW->iGraphicsMode);
2192 GetWorldTransform(hdc, &xformOld);
2193
2194 xform.eM11 = pPolyTextOutW->exScale;
2195 xform.eM12 = 0.0;
2196 xform.eM21 = 0.0;
2197 xform.eM22 = pPolyTextOutW->eyScale;
2198 xform.eDx = 0.0;
2199 xform.eDy = 0.0;
2200 SetWorldTransform(hdc, &xform);
2201
2202 /* Set up POLYTEXTW structures */
2203 for(i = 0; i < pPolyTextOutW->cStrings; i++)
2204 {
2205 polytextW[i].x = pPolyTextOutW->aemrtext[i].ptlReference.x;
2206 polytextW[i].y = pPolyTextOutW->aemrtext[i].ptlReference.y;
2207 polytextW[i].n = pPolyTextOutW->aemrtext[i].nChars;
2208 polytextW[i].lpstr = (LPCWSTR)((const BYTE *)mr + pPolyTextOutW->aemrtext[i].offString);
2209 polytextW[i].uiFlags = pPolyTextOutW->aemrtext[i].fOptions;
2210 polytextW[i].rcl.left = pPolyTextOutW->aemrtext[i].rcl.left;
2211 polytextW[i].rcl.right = pPolyTextOutW->aemrtext[i].rcl.right;
2212 polytextW[i].rcl.top = pPolyTextOutW->aemrtext[i].rcl.top;
2213 polytextW[i].rcl.bottom = pPolyTextOutW->aemrtext[i].rcl.bottom;
2214 polytextW[i].pdx = (int *)((BYTE *)mr + pPolyTextOutW->aemrtext[i].offDx);
2215 }
2216 PolyTextOutW(hdc, polytextW, pPolyTextOutW->cStrings);
2217 HeapFree(GetProcessHeap(), 0, polytextW);
2218
2219 SetWorldTransform(hdc, &xformOld);
2220 SetGraphicsMode(hdc, gModeOld);
2221 break;
2222 }
2223
2224 case EMR_FILLRGN:
2225 {
2226 const EMRFILLRGN *pFillRgn = (const EMRFILLRGN *)mr;
2227 HRGN hRgn = ExtCreateRegion(NULL, pFillRgn->cbRgnData, (const RGNDATA *)pFillRgn->RgnData);
2228 FillRgn(hdc,
2229 hRgn,
2230 (handletable->objectHandle)[pFillRgn->ihBrush]);
2231 DeleteObject(hRgn);
2232 break;
2233 }
2234
2235 case EMR_FRAMERGN:
2236 {
2237 const EMRFRAMERGN *pFrameRgn = (const EMRFRAMERGN *)mr;
2238 HRGN hRgn = ExtCreateRegion(NULL, pFrameRgn->cbRgnData, (const RGNDATA *)pFrameRgn->RgnData);
2239 FrameRgn(hdc,
2240 hRgn,
2241 (handletable->objectHandle)[pFrameRgn->ihBrush],
2242 pFrameRgn->szlStroke.cx,
2243 pFrameRgn->szlStroke.cy);
2244 DeleteObject(hRgn);
2245 break;
2246 }
2247
2248 case EMR_INVERTRGN:
2249 {
2250 const EMRINVERTRGN *pInvertRgn = (const EMRINVERTRGN *)mr;
2251 HRGN hRgn = ExtCreateRegion(NULL, pInvertRgn->cbRgnData, (const RGNDATA *)pInvertRgn->RgnData);
2252 InvertRgn(hdc, hRgn);
2253 DeleteObject(hRgn);
2254 break;
2255 }
2256
2257 case EMR_PAINTRGN:
2258 {
2259 const EMRPAINTRGN *pPaintRgn = (const EMRPAINTRGN *)mr;
2260 HRGN hRgn = ExtCreateRegion(NULL, pPaintRgn->cbRgnData, (const RGNDATA *)pPaintRgn->RgnData);
2261 PaintRgn(hdc, hRgn);
2262 DeleteObject(hRgn);
2263 break;
2264 }
2265
2266 case EMR_SETTEXTJUSTIFICATION:
2267 {
2268 const EMRSETTEXTJUSTIFICATION *pSetTextJust = (const EMRSETTEXTJUSTIFICATION *)mr;
2269 SetTextJustification(hdc, pSetTextJust->nBreakExtra, pSetTextJust->nBreakCount);
2270 break;
2271 }
2272
2273 case EMR_SETLAYOUT:
2274 {
2275 const EMRSETLAYOUT *pSetLayout = (const EMRSETLAYOUT *)mr;
2276 SetLayout(hdc, pSetLayout->iMode);
2277 break;
2278 }
2279
2280 case EMR_GRADIENTFILL:
2281 {
2282 EMRGRADIENTFILL *grad = (EMRGRADIENTFILL *)mr;
2283 GdiGradientFill( hdc, grad->Ver, grad->nVer, grad->Ver + grad->nVer,
2284 grad->nTri, grad->ulMode );
2285 break;
2286 }
2287
2288 case EMR_DRAWESCAPE:
2289 {
2290 PEMRESCAPE pemr = (PEMRESCAPE)mr;
2291 DrawEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data );
2292 break;
2293 }
2294
2295 case EMR_EXTESCAPE:
2296 {
2297 PEMRESCAPE pemr = (PEMRESCAPE)mr;
2298 ExtEscape( hdc, pemr->iEsc, pemr->cjIn, (LPCSTR)pemr->Data, 0, NULL );
2299 break;
2300 }
2301
2302 case EMR_NAMEDESCAPE:
2303 {
2304 PEMRNAMEDESCAPE pemr = (PEMRNAMEDESCAPE)mr;
2305 INT rounded_size = (pemr->cjIn+3) & ~3;
2306 NamedEscape( hdc, (PWCHAR)&pemr->Data[rounded_size], pemr->iEsc, pemr->cjIn, (LPSTR)pemr->Data, 0, NULL );
2307 break;
2308 }
2309
2310 case EMR_GLSRECORD:
2311 case EMR_GLSBOUNDEDRECORD:
2312 case EMR_STARTDOC:
2313 case EMR_SMALLTEXTOUT:
2314 case EMR_FORCEUFIMAPPING:
2315 case EMR_COLORCORRECTPALETTE:
2316 case EMR_SETICMPROFILEA:
2317 case EMR_SETICMPROFILEW:
2318 case EMR_TRANSPARENTBLT:
2319 case EMR_SETLINKEDUFI:
2320 case EMR_COLORMATCHTOTARGETW:
2321 case EMR_CREATECOLORSPACEW:
2322
2323 default:
2324 /* From docs: If PlayEnhMetaFileRecord doesn't recognize a
2325 record then ignore and return TRUE. */
2326 FIXME("type %d is unimplemented\n", type);
2327 break;
2328 }
2329 tmprc.left = tmprc.top = 0;
2330 tmprc.right = tmprc.bottom = 1000;
2331 LPtoDP(hdc, (POINT*)&tmprc, 2);
2332 TRACE("L:0,0 - 1000,1000 -> D:%s\n", wine_dbgstr_rect(&tmprc));
2333
2334 return TRUE;
2335 }
2336
2337 /*****************************************************************************
2338 *
2339 * EnumEnhMetaFile (GDI32.@)
2340 *
2341 * Walk an enhanced metafile, calling a user-specified function _EnhMetaFunc_
2342 * for each
2343 * record. Returns when either every record has been used or
2344 * when _EnhMetaFunc_ returns FALSE.
2345 *
2346 *
2347 * RETURNS
2348 * TRUE if every record is used, FALSE if any invocation of _EnhMetaFunc_
2349 * returns FALSE.
2350 *
2351 * BUGS
2352 * Ignores rect.
2353 *
2354 * NOTES
2355 * This function behaves differently in Win9x and WinNT.
2356 *
2357 * In WinNT, the DC's world transform is updated as the EMF changes
2358 * the Window/Viewport Extent and Origin or its world transform.
2359 * The actual Window/Viewport Extent and Origin are left untouched.
2360 *
2361 * In Win9x, the DC is left untouched, and PlayEnhMetaFileRecord
2362 * updates the scaling itself but only just before a record that
2363 * writes anything to the DC.
2364 *
2365 * I'm not sure where the data (enum_emh_data) is stored in either
2366 * version. For this implementation, it is stored before the handle
2367 * table, but it could be stored in the DC, in the EMF handle or in
2368 * TLS.
2369 * MJM 5 Oct 2002
2370 */
EnumEnhMetaFile(HDC hdc,HENHMETAFILE hmf,ENHMFENUMPROC callback,LPVOID data,const RECT * lpRect)2371 BOOL WINAPI EnumEnhMetaFile(
2372 HDC hdc, /* [in] device context to pass to _EnhMetaFunc_ */
2373 HENHMETAFILE hmf, /* [in] EMF to walk */
2374 ENHMFENUMPROC callback, /* [in] callback function */
2375 LPVOID data, /* [in] optional data for callback function */
2376 const RECT *lpRect /* [in] bounding rectangle for rendered metafile */
2377 )
2378 {
2379 BOOL ret;
2380 ENHMETAHEADER *emh;
2381 ENHMETARECORD *emr;
2382 DWORD offset;
2383 UINT i;
2384 HANDLETABLE *ht;
2385 INT savedMode = 0;
2386 XFORM savedXform;
2387 HPEN hPen = NULL;
2388 HBRUSH hBrush = NULL;
2389 HFONT hFont = NULL;
2390 HRGN hRgn = NULL;
2391 enum_emh_data *info;
2392 SIZE vp_size, win_size;
2393 POINT vp_org, win_org;
2394 INT mapMode = MM_TEXT, old_align = 0, old_rop2 = 0, old_arcdir = 0, old_polyfill = 0, old_stretchblt = 0;
2395 COLORREF old_text_color = 0, old_bk_color = 0;
2396
2397 if(!lpRect && hdc)
2398 {
2399 SetLastError(ERROR_INVALID_PARAMETER);
2400 return FALSE;
2401 }
2402
2403 emh = EMF_GetEnhMetaHeader(hmf);
2404 if(!emh) {
2405 SetLastError(ERROR_INVALID_HANDLE);
2406 return FALSE;
2407 }
2408
2409 info = HeapAlloc( GetProcessHeap(), 0,
2410 sizeof (enum_emh_data) + sizeof(HANDLETABLE) * emh->nHandles );
2411 if(!info)
2412 {
2413 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2414 return FALSE;
2415 }
2416 info->state.mode = MM_TEXT;
2417 info->state.wndOrgX = 0;
2418 info->state.wndOrgY = 0;
2419 info->state.wndExtX = 1;
2420 info->state.wndExtY = 1;
2421 info->state.vportOrgX = 0;
2422 info->state.vportOrgY = 0;
2423 info->state.vportExtX = 1;
2424 info->state.vportExtY = 1;
2425 info->state.world_transform.eM11 = info->state.world_transform.eM22 = 1;
2426 info->state.world_transform.eM12 = info->state.world_transform.eM21 = 0;
2427 info->state.world_transform.eDx = info->state.world_transform.eDy = 0;
2428
2429 info->state.next = NULL;
2430 info->save_level = 0;
2431 info->saved_state = NULL;
2432 info->init_transform = info->state.world_transform;
2433
2434 ht = (HANDLETABLE*) &info[1];
2435 ht->objectHandle[0] = hmf;
2436 for(i = 1; i < emh->nHandles; i++)
2437 ht->objectHandle[i] = NULL;
2438
2439 if(hdc && !is_meta_dc( hdc ))
2440 {
2441 savedMode = SetGraphicsMode(hdc, GM_ADVANCED);
2442 GetWorldTransform(hdc, &savedXform);
2443 GetViewportExtEx(hdc, &vp_size);
2444 GetWindowExtEx(hdc, &win_size);
2445 GetViewportOrgEx(hdc, &vp_org);
2446 GetWindowOrgEx(hdc, &win_org);
2447 mapMode = GetMapMode(hdc);
2448
2449 /* save DC */
2450 hPen = GetCurrentObject(hdc, OBJ_PEN);
2451 hBrush = GetCurrentObject(hdc, OBJ_BRUSH);
2452 hFont = GetCurrentObject(hdc, OBJ_FONT);
2453
2454 hRgn = CreateRectRgn(0, 0, 0, 0);
2455 if (!GetClipRgn(hdc, hRgn))
2456 {
2457 DeleteObject(hRgn);
2458 hRgn = 0;
2459 }
2460
2461 old_text_color = SetTextColor(hdc, RGB(0,0,0));
2462 old_bk_color = SetBkColor(hdc, RGB(0xff, 0xff, 0xff));
2463 old_align = SetTextAlign(hdc, 0);
2464 old_rop2 = SetROP2(hdc, R2_COPYPEN);
2465 old_arcdir = SetArcDirection(hdc, AD_COUNTERCLOCKWISE);
2466 old_polyfill = SetPolyFillMode(hdc, ALTERNATE);
2467 old_stretchblt = SetStretchBltMode(hdc, BLACKONWHITE);
2468
2469 if (!IS_WIN9X() )
2470 {
2471 /* WinNT combines the vp/win ext/org info into a transform */
2472 double xscale, yscale;
2473 xscale = (double)vp_size.cx / (double)win_size.cx;
2474 yscale = (double)vp_size.cy / (double)win_size.cy;
2475 info->init_transform.eM11 = xscale;
2476 info->init_transform.eM12 = 0.0;
2477 info->init_transform.eM21 = 0.0;
2478 info->init_transform.eM22 = yscale;
2479 info->init_transform.eDx = (double)vp_org.x - xscale * (double)win_org.x;
2480 info->init_transform.eDy = (double)vp_org.y - yscale * (double)win_org.y;
2481
2482 CombineTransform(&info->init_transform, &savedXform, &info->init_transform);
2483 }
2484
2485 if ( lpRect && WIDTH(emh->rclFrame) && HEIGHT(emh->rclFrame) )
2486 {
2487 double xSrcPixSize, ySrcPixSize, xscale, yscale;
2488 XFORM xform;
2489
2490 TRACE("rect: %s. rclFrame: (%d,%d)-(%d,%d)\n", wine_dbgstr_rect(lpRect),
2491 emh->rclFrame.left, emh->rclFrame.top, emh->rclFrame.right,
2492 emh->rclFrame.bottom);
2493
2494 xSrcPixSize = (double) emh->szlMillimeters.cx / emh->szlDevice.cx;
2495 ySrcPixSize = (double) emh->szlMillimeters.cy / emh->szlDevice.cy;
2496 xscale = (double) WIDTH(*lpRect) * 100.0 /
2497 WIDTH(emh->rclFrame) * xSrcPixSize;
2498 yscale = (double) HEIGHT(*lpRect) * 100.0 /
2499 HEIGHT(emh->rclFrame) * ySrcPixSize;
2500 TRACE("xscale = %f, yscale = %f\n", xscale, yscale);
2501
2502 xform.eM11 = xscale;
2503 xform.eM12 = 0;
2504 xform.eM21 = 0;
2505 xform.eM22 = yscale;
2506 xform.eDx = (double) lpRect->left - (double) WIDTH(*lpRect) / WIDTH(emh->rclFrame) * emh->rclFrame.left;
2507 xform.eDy = (double) lpRect->top - (double) HEIGHT(*lpRect) / HEIGHT(emh->rclFrame) * emh->rclFrame.top;
2508
2509 CombineTransform(&info->init_transform, &xform, &info->init_transform);
2510 }
2511
2512 /* WinNT resets the current vp/win org/ext */
2513 if ( !IS_WIN9X() )
2514 {
2515 SetMapMode(hdc, MM_TEXT);
2516 SetWindowOrgEx(hdc, 0, 0, NULL);
2517 SetViewportOrgEx(hdc, 0, 0, NULL);
2518 EMF_Update_MF_Xform(hdc, info);
2519 }
2520 }
2521
2522 ret = TRUE;
2523 offset = 0;
2524 while(ret && offset < emh->nBytes)
2525 {
2526 emr = (ENHMETARECORD *)((char *)emh + offset);
2527
2528 if (offset + 8 > emh->nBytes ||
2529 offset > offset + emr->nSize ||
2530 offset + emr->nSize > emh->nBytes)
2531 {
2532 WARN("record truncated\n");
2533 break;
2534 }
2535
2536 /* In Win9x mode we update the xform if the record will produce output */
2537 if (hdc && IS_WIN9X() && emr_produces_output(emr->iType))
2538 EMF_Update_MF_Xform(hdc, info);
2539
2540 TRACE("Calling EnumFunc with record %s, size %d\n", get_emr_name(emr->iType), emr->nSize);
2541 ret = (*callback)(hdc, ht, emr, emh->nHandles, (LPARAM)data);
2542 offset += emr->nSize;
2543 }
2544
2545 if (hdc && !is_meta_dc( hdc ))
2546 {
2547 SetStretchBltMode(hdc, old_stretchblt);
2548 SetPolyFillMode(hdc, old_polyfill);
2549 SetArcDirection(hdc, old_arcdir);
2550 SetROP2(hdc, old_rop2);
2551 SetTextAlign(hdc, old_align);
2552 SetBkColor(hdc, old_bk_color);
2553 SetTextColor(hdc, old_text_color);
2554
2555 /* restore DC */
2556 SelectObject(hdc, hBrush);
2557 SelectObject(hdc, hPen);
2558 SelectObject(hdc, hFont);
2559 ExtSelectClipRgn(hdc, hRgn, RGN_COPY);
2560 DeleteObject(hRgn);
2561
2562 SetWorldTransform(hdc, &savedXform);
2563 if (savedMode)
2564 SetGraphicsMode(hdc, savedMode);
2565 SetMapMode(hdc, mapMode);
2566 SetWindowOrgEx(hdc, win_org.x, win_org.y, NULL);
2567 SetWindowExtEx(hdc, win_size.cx, win_size.cy, NULL);
2568 SetViewportOrgEx(hdc, vp_org.x, vp_org.y, NULL);
2569 SetViewportExtEx(hdc, vp_size.cx, vp_size.cy, NULL);
2570 }
2571
2572 for(i = 1; i < emh->nHandles; i++) /* Don't delete element 0 (hmf) */
2573 if( (ht->objectHandle)[i] )
2574 DeleteObject( (ht->objectHandle)[i] );
2575
2576 while (info->saved_state)
2577 {
2578 EMF_dc_state *state = info->saved_state;
2579 info->saved_state = info->saved_state->next;
2580 HeapFree( GetProcessHeap(), 0, state );
2581 }
2582 HeapFree( GetProcessHeap(), 0, info );
2583 return ret;
2584 }
2585
EMF_PlayEnhMetaFileCallback(HDC hdc,HANDLETABLE * ht,const ENHMETARECORD * emr,INT handles,LPARAM data)2586 static INT CALLBACK EMF_PlayEnhMetaFileCallback(HDC hdc, HANDLETABLE *ht,
2587 const ENHMETARECORD *emr,
2588 INT handles, LPARAM data)
2589 {
2590 return PlayEnhMetaFileRecord(hdc, ht, emr, handles);
2591 }
2592
2593 /**************************************************************************
2594 * PlayEnhMetaFile (GDI32.@)
2595 *
2596 * Renders an enhanced metafile into a specified rectangle *lpRect
2597 * in device context hdc.
2598 *
2599 * RETURNS
2600 * Success: TRUE
2601 * Failure: FALSE
2602 */
PlayEnhMetaFile(HDC hdc,HENHMETAFILE hmf,const RECT * lpRect)2603 BOOL WINAPI PlayEnhMetaFile(
2604 HDC hdc, /* [in] DC to render into */
2605 HENHMETAFILE hmf, /* [in] metafile to render */
2606 const RECT *lpRect /* [in] rectangle to place metafile inside */
2607 )
2608 {
2609 return EnumEnhMetaFile(hdc, hmf, EMF_PlayEnhMetaFileCallback, NULL, lpRect);
2610 }
2611
2612 /*****************************************************************************
2613 * DeleteEnhMetaFile (GDI32.@)
2614 *
2615 * Deletes an enhanced metafile and frees the associated storage.
2616 */
DeleteEnhMetaFile(HENHMETAFILE hmf)2617 BOOL WINAPI DeleteEnhMetaFile(HENHMETAFILE hmf)
2618 {
2619 return EMF_Delete_HENHMETAFILE( hmf );
2620 }
2621
2622 /*****************************************************************************
2623 * CopyEnhMetaFileA (GDI32.@)
2624 *
2625 * Duplicate an enhanced metafile.
2626 *
2627 *
2628 */
CopyEnhMetaFileA(HENHMETAFILE hmfSrc,LPCSTR file)2629 HENHMETAFILE WINAPI CopyEnhMetaFileA(
2630 HENHMETAFILE hmfSrc,
2631 LPCSTR file)
2632 {
2633 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
2634 HENHMETAFILE hmfDst;
2635
2636 if(!emrSrc) return FALSE;
2637 if (!file) {
2638 emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
2639 memcpy( emrDst, emrSrc, emrSrc->nBytes );
2640 hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE );
2641 if (!hmfDst)
2642 HeapFree( GetProcessHeap(), 0, emrDst );
2643 } else {
2644 HANDLE hFile;
2645 DWORD w;
2646 hFile = CreateFileA( file, GENERIC_WRITE | GENERIC_READ, 0,
2647 NULL, CREATE_ALWAYS, 0, 0);
2648 WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
2649 CloseHandle( hFile );
2650 /* Reopen file for reading only, so that apps can share
2651 read access to the file while hmf is still valid */
2652 hFile = CreateFileA( file, GENERIC_READ, FILE_SHARE_READ,
2653 NULL, OPEN_EXISTING, 0, 0);
2654 if(hFile == INVALID_HANDLE_VALUE) {
2655 ERR("Can't reopen emf for reading\n");
2656 return 0;
2657 }
2658 hmfDst = EMF_GetEnhMetaFile( hFile );
2659 CloseHandle( hFile );
2660 }
2661 return hmfDst;
2662 }
2663
2664 /*****************************************************************************
2665 * CopyEnhMetaFileW (GDI32.@)
2666 *
2667 * See CopyEnhMetaFileA.
2668 *
2669 *
2670 */
CopyEnhMetaFileW(HENHMETAFILE hmfSrc,LPCWSTR file)2671 HENHMETAFILE WINAPI CopyEnhMetaFileW(
2672 HENHMETAFILE hmfSrc,
2673 LPCWSTR file)
2674 {
2675 ENHMETAHEADER *emrSrc = EMF_GetEnhMetaHeader( hmfSrc ), *emrDst;
2676 HENHMETAFILE hmfDst;
2677
2678 if(!emrSrc) return FALSE;
2679 if (!file) {
2680 emrDst = HeapAlloc( GetProcessHeap(), 0, emrSrc->nBytes );
2681 memcpy( emrDst, emrSrc, emrSrc->nBytes );
2682 hmfDst = EMF_Create_HENHMETAFILE( emrDst, emrSrc->nBytes, FALSE );
2683 if (!hmfDst)
2684 HeapFree( GetProcessHeap(), 0, emrDst );
2685 } else {
2686 HANDLE hFile;
2687 DWORD w;
2688 hFile = CreateFileW( file, GENERIC_WRITE | GENERIC_READ, 0,
2689 NULL, CREATE_ALWAYS, 0, 0);
2690 WriteFile( hFile, emrSrc, emrSrc->nBytes, &w, NULL);
2691 CloseHandle( hFile );
2692 /* Reopen file for reading only, so that apps can share
2693 read access to the file while hmf is still valid */
2694 hFile = CreateFileW( file, GENERIC_READ, FILE_SHARE_READ,
2695 NULL, OPEN_EXISTING, 0, 0);
2696 if(hFile == INVALID_HANDLE_VALUE) {
2697 ERR("Can't reopen emf for reading\n");
2698 return 0;
2699 }
2700 hmfDst = EMF_GetEnhMetaFile( hFile );
2701 CloseHandle( hFile );
2702 }
2703 return hmfDst;
2704 }
2705
2706
2707 /* Struct to be used to be passed in the LPVOID parameter for cbEnhPaletteCopy */
2708 typedef struct tagEMF_PaletteCopy
2709 {
2710 UINT cEntries;
2711 LPPALETTEENTRY lpPe;
2712 } EMF_PaletteCopy;
2713
2714 /***************************************************************
2715 * Find the EMR_EOF record and then use it to find the
2716 * palette entries for this enhanced metafile.
2717 * The lpData is actually a pointer to an EMF_PaletteCopy struct
2718 * which contains the max number of elements to copy and where
2719 * to copy them to.
2720 *
2721 * NOTE: To be used by GetEnhMetaFilePaletteEntries only!
2722 */
cbEnhPaletteCopy(HDC a,HANDLETABLE * b,const ENHMETARECORD * lpEMR,INT c,LPARAM lpData)2723 static INT CALLBACK cbEnhPaletteCopy( HDC a,
2724 HANDLETABLE *b,
2725 const ENHMETARECORD *lpEMR,
2726 INT c,
2727 LPARAM lpData )
2728 {
2729
2730 if ( lpEMR->iType == EMR_EOF )
2731 {
2732 const EMREOF *lpEof = (const EMREOF *)lpEMR;
2733 EMF_PaletteCopy* info = (EMF_PaletteCopy*)lpData;
2734 DWORD dwNumPalToCopy = min( lpEof->nPalEntries, info->cEntries );
2735
2736 TRACE( "copying 0x%08x palettes\n", dwNumPalToCopy );
2737
2738 memcpy( info->lpPe, (LPCSTR)lpEof + lpEof->offPalEntries,
2739 sizeof( *(info->lpPe) ) * dwNumPalToCopy );
2740
2741 /* Update the passed data as a return code */
2742 info->lpPe = NULL; /* Palettes were copied! */
2743 info->cEntries = dwNumPalToCopy;
2744
2745 return FALSE; /* That's all we need */
2746 }
2747
2748 return TRUE;
2749 }
2750
2751 /*****************************************************************************
2752 * GetEnhMetaFilePaletteEntries (GDI32.@)
2753 *
2754 * Copy the palette and report size
2755 *
2756 * BUGS: Error codes (SetLastError) are not set on failures
2757 */
GetEnhMetaFilePaletteEntries(HENHMETAFILE hEmf,UINT cEntries,LPPALETTEENTRY lpPe)2758 UINT WINAPI GetEnhMetaFilePaletteEntries( HENHMETAFILE hEmf,
2759 UINT cEntries,
2760 LPPALETTEENTRY lpPe )
2761 {
2762 ENHMETAHEADER* enhHeader = EMF_GetEnhMetaHeader( hEmf );
2763 EMF_PaletteCopy infoForCallBack;
2764
2765 TRACE( "(%p,%d,%p)\n", hEmf, cEntries, lpPe );
2766
2767 if (!enhHeader) return 0;
2768
2769 /* First check if there are any palettes associated with
2770 this metafile. */
2771 if ( enhHeader->nPalEntries == 0 ) return 0;
2772
2773 /* Is the user requesting the number of palettes? */
2774 if ( lpPe == NULL ) return enhHeader->nPalEntries;
2775
2776 /* Copy cEntries worth of PALETTEENTRY structs into the buffer */
2777 infoForCallBack.cEntries = cEntries;
2778 infoForCallBack.lpPe = lpPe;
2779
2780 if ( !EnumEnhMetaFile( 0, hEmf, cbEnhPaletteCopy,
2781 &infoForCallBack, 0 ) )
2782 return GDI_ERROR;
2783
2784 /* Verify that the callback executed correctly */
2785 if ( infoForCallBack.lpPe != NULL )
2786 {
2787 /* Callback proc had error! */
2788 ERR( "cbEnhPaletteCopy didn't execute correctly\n" );
2789 return GDI_ERROR;
2790 }
2791
2792 return infoForCallBack.cEntries;
2793 }
2794
2795 /******************************************************************
2796 * extract_emf_from_comment
2797 *
2798 * If the WMF was created by GetWinMetaFileBits, then extract the
2799 * original EMF that is stored in MFCOMMENT chunks.
2800 */
extract_emf_from_comment(const BYTE * buf,UINT mf_size)2801 static HENHMETAFILE extract_emf_from_comment( const BYTE *buf, UINT mf_size )
2802 {
2803 METAHEADER *mh = (METAHEADER *)buf;
2804 METARECORD *mr;
2805 emf_in_wmf_comment *chunk;
2806 WORD checksum = 0;
2807 DWORD size = 0, remaining, chunks;
2808 BYTE *emf_bits = NULL, *ptr;
2809 UINT offset;
2810 HENHMETAFILE emf = NULL;
2811
2812 if (mf_size < sizeof(*mh)) return NULL;
2813
2814 for (offset = mh->mtHeaderSize * 2; offset < mf_size; offset += (mr->rdSize * 2))
2815 {
2816 mr = (METARECORD *)((char *)mh + offset);
2817 chunk = (emf_in_wmf_comment *)(mr->rdParm + 2);
2818
2819 if (mr->rdFunction != META_ESCAPE || mr->rdParm[0] != MFCOMMENT) goto done;
2820 if (chunk->magic != WMFC_MAGIC) goto done;
2821
2822 if (!emf_bits)
2823 {
2824 size = remaining = chunk->emf_size;
2825 chunks = chunk->num_chunks;
2826 emf_bits = ptr = HeapAlloc( GetProcessHeap(), 0, size );
2827 if (!emf_bits) goto done;
2828 }
2829 if (chunk->chunk_size > remaining) goto done;
2830 remaining -= chunk->chunk_size;
2831 if (chunk->remaining_size != remaining) goto done;
2832 memcpy( ptr, chunk->emf_data, chunk->chunk_size );
2833 ptr += chunk->chunk_size;
2834 if (--chunks == 0) break;
2835 }
2836
2837 for (offset = 0; offset < mf_size / 2; offset++)
2838 checksum += *((WORD *)buf + offset);
2839 if (checksum) goto done;
2840
2841 emf = SetEnhMetaFileBits( size, emf_bits );
2842
2843 done:
2844 HeapFree( GetProcessHeap(), 0, emf_bits );
2845 return emf;
2846 }
2847
2848 typedef struct wmf_in_emf_comment
2849 {
2850 DWORD ident;
2851 DWORD iComment;
2852 DWORD nVersion;
2853 DWORD nChecksum;
2854 DWORD fFlags;
2855 DWORD cbWinMetaFile;
2856 } wmf_in_emf_comment;
2857
2858 /******************************************************************
2859 * SetWinMetaFileBits (GDI32.@)
2860 *
2861 * Translate from old style to new style.
2862 *
2863 */
SetWinMetaFileBits(UINT cbBuffer,const BYTE * lpbBuffer,HDC hdcRef,const METAFILEPICT * lpmfp)2864 HENHMETAFILE WINAPI SetWinMetaFileBits(UINT cbBuffer, const BYTE *lpbBuffer, HDC hdcRef,
2865 const METAFILEPICT *lpmfp)
2866 {
2867 static const WCHAR szDisplayW[] = { 'D','I','S','P','L','A','Y','\0' };
2868 HMETAFILE hmf = NULL;
2869 HENHMETAFILE ret = NULL;
2870 HDC hdc = NULL, hdcdisp = NULL;
2871 RECT rc, *prcFrame = NULL;
2872 LONG mm, xExt, yExt;
2873 INT horzsize, vertsize, horzres, vertres;
2874
2875 TRACE("(%d, %p, %p, %p)\n", cbBuffer, lpbBuffer, hdcRef, lpmfp);
2876
2877 hmf = SetMetaFileBitsEx(cbBuffer, lpbBuffer);
2878 if(!hmf)
2879 {
2880 WARN("SetMetaFileBitsEx failed\n");
2881 return NULL;
2882 }
2883
2884 ret = extract_emf_from_comment( lpbBuffer, cbBuffer );
2885 if (ret) return ret;
2886
2887 if(!hdcRef)
2888 hdcRef = hdcdisp = CreateDCW(szDisplayW, NULL, NULL, NULL);
2889
2890 if (lpmfp)
2891 {
2892 TRACE("mm = %d %dx%d\n", lpmfp->mm, lpmfp->xExt, lpmfp->yExt);
2893
2894 mm = lpmfp->mm;
2895 xExt = lpmfp->xExt;
2896 yExt = lpmfp->yExt;
2897 }
2898 else
2899 {
2900 TRACE("lpmfp == NULL\n");
2901
2902 /* Use the whole device surface */
2903 mm = MM_ANISOTROPIC;
2904 xExt = 0;
2905 yExt = 0;
2906 }
2907
2908 if (mm == MM_ISOTROPIC || mm == MM_ANISOTROPIC)
2909 {
2910 if (xExt < 0 || yExt < 0)
2911 {
2912 /* Use the whole device surface */
2913 xExt = 0;
2914 yExt = 0;
2915 }
2916
2917 /* Use the x and y extents as the frame box */
2918 if (xExt && yExt)
2919 {
2920 rc.left = rc.top = 0;
2921 rc.right = xExt;
2922 rc.bottom = yExt;
2923 prcFrame = &rc;
2924 }
2925 }
2926
2927 if(!(hdc = CreateEnhMetaFileW(hdcRef, NULL, prcFrame, NULL)))
2928 {
2929 ERR("CreateEnhMetaFile failed\n");
2930 goto end;
2931 }
2932
2933 /*
2934 * Write the original METAFILE into the enhanced metafile.
2935 * It is encapsulated in a GDICOMMENT_WINDOWS_METAFILE record.
2936 */
2937 if (mm != MM_TEXT)
2938 {
2939 wmf_in_emf_comment *mfcomment;
2940 UINT mfcomment_size;
2941
2942 mfcomment_size = sizeof (*mfcomment) + cbBuffer;
2943 mfcomment = HeapAlloc(GetProcessHeap(), 0, mfcomment_size);
2944 if (mfcomment)
2945 {
2946 mfcomment->ident = GDICOMMENT_IDENTIFIER;
2947 mfcomment->iComment = GDICOMMENT_WINDOWS_METAFILE;
2948 mfcomment->nVersion = 0x00000300;
2949 mfcomment->nChecksum = 0; /* FIXME */
2950 mfcomment->fFlags = 0;
2951 mfcomment->cbWinMetaFile = cbBuffer;
2952 memcpy(&mfcomment[1], lpbBuffer, cbBuffer);
2953 GdiComment(hdc, mfcomment_size, (BYTE*) mfcomment);
2954 HeapFree(GetProcessHeap(), 0, mfcomment);
2955 }
2956 SetMapMode(hdc, mm);
2957 }
2958
2959
2960 horzsize = GetDeviceCaps(hdcRef, HORZSIZE);
2961 vertsize = GetDeviceCaps(hdcRef, VERTSIZE);
2962 horzres = GetDeviceCaps(hdcRef, HORZRES);
2963 vertres = GetDeviceCaps(hdcRef, VERTRES);
2964
2965 if (!xExt || !yExt)
2966 {
2967 /* Use the whole device surface */
2968 xExt = horzres;
2969 yExt = vertres;
2970 }
2971 else
2972 {
2973 xExt = MulDiv(xExt, horzres, 100 * horzsize);
2974 yExt = MulDiv(yExt, vertres, 100 * vertsize);
2975 }
2976
2977 /* set the initial viewport:window ratio as 1:1 */
2978 SetViewportExtEx(hdc, xExt, yExt, NULL);
2979 SetWindowExtEx(hdc, xExt, yExt, NULL);
2980
2981 PlayMetaFile(hdc, hmf);
2982
2983 ret = CloseEnhMetaFile(hdc);
2984 end:
2985 if (hdcdisp) DeleteDC(hdcdisp);
2986 DeleteMetaFile(hmf);
2987 return ret;
2988 }
2989