xref: /reactos/win32ss/gdi/gdi32/wine/emfdc.c (revision 8767aada)
1 /*
2  * Enhanced MetaFile recording functions
3  *
4  * Copyright 1999 Huw D M Davies
5  * Copyright 2016 Alexandre Julliard
6  * Copyright 2021 Jacek Caban for CodeWeavers
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 #include "config.h"
23 
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winnls.h"
32 #include "winerror.h"
33 #include "gdi_private.h"
34 #include "wine/wingdi16.h"
35 #include "wine/debug.h"
36 #ifdef __REACTOS__
37 #include "wine/winternl.h"
38 #else
39 #include "winternl.h"
40 #endif
41 
42 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
43 
44 struct emf
45 {
46     ENHMETAHEADER  *emh;
47     WINEDC  *dc_attr;
48     UINT     handles_size, cur_handles;
49     HGDIOBJ *handles;
50     HANDLE   file;
51     HBRUSH   dc_brush;
52     HPEN     dc_pen;
53     BOOL     path;
54 };
55 
56 #define HANDLE_LIST_INC 20
57 static const RECTL empty_bounds = { 0, 0, -1, -1 };
58 
emfdc_record(struct emf * emf,EMR * emr)59 static BOOL emfdc_record( struct emf *emf, EMR *emr )
60 {
61     DWORD len, size;
62     ENHMETAHEADER *emh;
63 
64     TRACE( "record %d, size %d\n", emr->iType, emr->nSize );
65 
66     assert( !(emr->nSize & 3) );
67 
68     emf->emh->nBytes += emr->nSize;
69     emf->emh->nRecords++;
70 
71     size = HeapSize( GetProcessHeap(), 0, emf->emh );
72     len = emf->emh->nBytes;
73     if (len > size)
74     {
75         size += (size / 2) + emr->nSize;
76         emh = HeapReAlloc( GetProcessHeap(), 0, emf->emh, size );
77         if (!emh) return FALSE;
78         emf->emh = emh;
79     }
80     memcpy( (char *)emf->emh + emf->emh->nBytes - emr->nSize, emr, emr->nSize );
81     return TRUE;
82 }
83 
emfdc_update_bounds(struct emf * emf,RECTL * rect)84 static void emfdc_update_bounds( struct emf *emf, RECTL *rect )
85 {
86     RECTL *bounds = &emf->dc_attr->emf_bounds;
87     RECTL vport_rect = *rect;
88 
89     LPtoDP( emf->dc_attr->hdc, (POINT *)&vport_rect, 2 );
90 
91     /* The coordinate systems may be mirrored
92        (LPtoDP handles points, not rectangles) */
93     if (vport_rect.left > vport_rect.right)
94     {
95         LONG temp = vport_rect.right;
96         vport_rect.right = vport_rect.left;
97         vport_rect.left = temp;
98     }
99     if (vport_rect.top > vport_rect.bottom)
100     {
101         LONG temp = vport_rect.bottom;
102         vport_rect.bottom = vport_rect.top;
103         vport_rect.top = temp;
104     }
105 
106     if (bounds->left > bounds->right)
107     {
108         /* first bounding rectangle */
109         *bounds = vport_rect;
110     }
111     else
112     {
113         bounds->left   = min(bounds->left,   vport_rect.left);
114         bounds->top    = min(bounds->top,    vport_rect.top);
115         bounds->right  = max(bounds->right,  vport_rect.right);
116         bounds->bottom = max(bounds->bottom, vport_rect.bottom);
117     }
118 }
119 
get_bitmap_info(HDC * hdc,HBITMAP * bitmap,BITMAPINFO * info)120 static UINT get_bitmap_info( HDC *hdc, HBITMAP *bitmap, BITMAPINFO *info )
121 {
122     HBITMAP blit_bitmap;
123     HDC blit_dc;
124     UINT info_size, bpp;
125     DIBSECTION dib;
126 
127     if (!(info_size = GetObjectW( *bitmap, sizeof(dib), &dib ))) return 0;
128 
129     if (info_size == sizeof(dib))
130     {
131         blit_dc = *hdc;
132         blit_bitmap = *bitmap;
133     }
134     else
135     {
136         unsigned char dib_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors)
137                               + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)];
138         BITMAPINFO *dib_info = (BITMAPINFO *)dib_info_buffer;
139         BITMAP bmp = dib.dsBm;
140         HPALETTE palette;
141         void *bits;
142 
143         assert( info_size == sizeof(BITMAP) );
144 
145         dib_info->bmiHeader.biSize = sizeof(dib_info->bmiHeader);
146         dib_info->bmiHeader.biWidth = bmp.bmWidth;
147         dib_info->bmiHeader.biHeight = bmp.bmHeight;
148         dib_info->bmiHeader.biPlanes = 1;
149         dib_info->bmiHeader.biBitCount = bmp.bmBitsPixel;
150         dib_info->bmiHeader.biCompression = BI_RGB;
151         dib_info->bmiHeader.biSizeImage = 0;
152         dib_info->bmiHeader.biXPelsPerMeter = 0;
153         dib_info->bmiHeader.biYPelsPerMeter = 0;
154         dib_info->bmiHeader.biClrUsed = 0;
155         dib_info->bmiHeader.biClrImportant = 0;
156         switch (dib_info->bmiHeader.biBitCount)
157         {
158         case 16:
159             ((DWORD *)dib_info->bmiColors)[0] = 0xf800;
160             ((DWORD *)dib_info->bmiColors)[1] = 0x07e0;
161             ((DWORD *)dib_info->bmiColors)[2] = 0x001f;
162             break;
163         case 32:
164             ((DWORD *)dib_info->bmiColors)[0] = 0xff0000;
165             ((DWORD *)dib_info->bmiColors)[1] = 0x00ff00;
166             ((DWORD *)dib_info->bmiColors)[2] = 0x0000ff;
167             break;
168         default:
169             if (dib_info->bmiHeader.biBitCount > 8) break;
170             if (!(palette = GetCurrentObject( *hdc, OBJ_PAL ))) return FALSE;
171             if (!GetPaletteEntries( palette, 0, 256, (PALETTEENTRY *)dib_info->bmiColors ))
172                 return FALSE;
173         }
174 
175         if (!(blit_dc = /*NtGdi*/CreateCompatibleDC( *hdc ))) return FALSE;
176         if (!(blit_bitmap = CreateDIBSection( blit_dc, dib_info, DIB_RGB_COLORS, &bits, NULL, 0 )))
177             goto err;
178         if (!SelectObject( blit_dc, blit_bitmap )) goto err;
179         if (!BitBlt( blit_dc, 0, 0, bmp.bmWidth, bmp.bmHeight, *hdc, 0, 0, SRCCOPY ))
180             goto err;
181     }
182     if (!GetDIBits( blit_dc, blit_bitmap, 0, INT_MAX, NULL, info, DIB_RGB_COLORS ))
183         goto err;
184 
185     bpp = info->bmiHeader.biBitCount;
186     if (bpp <= 8)
187         return sizeof(BITMAPINFOHEADER) + (1L << bpp) * sizeof(RGBQUAD);
188     else if (bpp == 16 || bpp == 32)
189         return sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
190 
191     return sizeof(BITMAPINFOHEADER);
192 
193 err:
194     if (blit_dc && blit_dc != *hdc) DeleteDC( blit_dc );
195     if (blit_bitmap && blit_bitmap != *bitmap) DeleteObject( blit_bitmap );
196     return 0;
197 }
198 
emfdc_add_handle(struct emf * emf,HGDIOBJ obj)199 static UINT emfdc_add_handle( struct emf *emf, HGDIOBJ obj )
200 {
201     UINT index;
202 
203     for (index = 0; index < emf->handles_size; index++)
204         if (emf->handles[index] == 0) break;
205 
206     if (index == emf->handles_size)
207     {
208         emf->handles_size += HANDLE_LIST_INC;
209         emf->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
210                                     emf->handles,
211                                     emf->handles_size * sizeof(emf->handles[0]) );
212     }
213     emf->handles[index] = get_full_gdi_handle( obj );
214 
215     emf->cur_handles++;
216     if (emf->cur_handles > emf->emh->nHandles)
217         emf->emh->nHandles++;
218 
219     return index + 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
220 }
221 
emfdc_find_object(struct emf * emf,HGDIOBJ obj)222 static UINT emfdc_find_object( struct emf *emf, HGDIOBJ obj )
223 {
224     UINT index;
225 
226     for (index = 0; index < emf->handles_size; index++)
227         if (emf->handles[index] == obj) return index + 1;
228 
229     return 0;
230 }
231 
emfdc_delete_object(HDC hdc,HGDIOBJ obj)232 void emfdc_delete_object( HDC hdc, HGDIOBJ obj )
233 {
234     WINEDC *dc_attr = get_dc_ptr( hdc );
235     struct emf *emf = dc_attr->emf;
236     EMRDELETEOBJECT emr;
237     UINT index;
238 
239     if(!(index = emfdc_find_object( emf, obj ))) return;
240 
241     emr.emr.iType = EMR_DELETEOBJECT;
242     emr.emr.nSize = sizeof(emr);
243     emr.ihObject = index;
244 
245     emfdc_record( emf, &emr.emr );
246 
247     emf->handles[index - 1] = 0;
248     emf->cur_handles--;
249 }
250 
emfdc_create_brush(struct emf * emf,HBRUSH brush)251 static DWORD emfdc_create_brush( struct emf *emf, HBRUSH brush )
252 {
253     DWORD index = 0;
254     LOGBRUSH logbrush;
255 
256     if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return 0;
257 
258     switch (logbrush.lbStyle) {
259     case BS_SOLID:
260     case BS_HATCHED:
261     case BS_NULL:
262         {
263             EMRCREATEBRUSHINDIRECT emr;
264             emr.emr.iType = EMR_CREATEBRUSHINDIRECT;
265             emr.emr.nSize = sizeof(emr);
266             emr.ihBrush = index = emfdc_add_handle( emf, brush );
267             emr.lb.lbStyle = logbrush.lbStyle;
268             emr.lb.lbColor = logbrush.lbColor;
269             emr.lb.lbHatch = logbrush.lbHatch;
270 
271             if(!emfdc_record( emf, &emr.emr ))
272                 index = 0;
273         }
274       break;
275     case BS_PATTERN:
276     case BS_DIBPATTERN:
277         {
278             unsigned char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors)
279                          + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)];
280             BITMAPINFO *info = (BITMAPINFO *)buffer;
281             EMRCREATEDIBPATTERNBRUSHPT *emr;
282             DWORD info_size;
283             UINT usage;
284 
285             if (!get_brush_bitmap_info( brush, info, NULL, &usage )) break;
286             info_size = get_dib_info_size( info, usage );
287 
288             emr = HeapAlloc( GetProcessHeap(), 0,
289                              sizeof(EMRCREATEDIBPATTERNBRUSHPT) + sizeof(DWORD) +
290                              info_size+info->bmiHeader.biSizeImage );
291             if(!emr) break;
292 
293             /* FIXME: There is an extra DWORD written by native before the BMI.
294              *        Not sure what it's meant to contain.
295              */
296             emr->offBmi = sizeof( EMRCREATEDIBPATTERNBRUSHPT ) + sizeof(DWORD);
297             *(DWORD *)(emr + 1) = 0x20000000;
298 
299             if (logbrush.lbStyle == BS_PATTERN && info->bmiHeader.biBitCount == 1)
300             {
301                 /* Presumably to reduce the size of the written EMF, MS supports an
302                  * undocumented iUsage value of 2, indicating a mono bitmap without the
303                  * 8 byte 2 entry black/white palette. Stupidly, they could have saved
304                  * over 20 bytes more by also ignoring the BITMAPINFO fields that are
305                  * irrelevant/constant for monochrome bitmaps.
306                  * FIXME: It may be that the DIB functions themselves accept this value.
307                  */
308                 emr->emr.iType = EMR_CREATEMONOBRUSH;
309                 usage = DIB_PAL_MONO;
310                 emr->cbBmi = sizeof( BITMAPINFOHEADER );
311             }
312             else
313             {
314                 emr->emr.iType = EMR_CREATEDIBPATTERNBRUSHPT;
315                 emr->cbBmi = info_size;
316             }
317             emr->ihBrush = index = emfdc_add_handle( emf, brush );
318             emr->iUsage = usage;
319             emr->offBits = emr->offBmi + emr->cbBmi;
320             emr->cbBits = info->bmiHeader.biSizeImage;
321             emr->emr.nSize = emr->offBits + emr->cbBits;
322 
323             if (info->bmiHeader.biClrUsed == 1 << info->bmiHeader.biBitCount)
324                 info->bmiHeader.biClrUsed = 0;
325             memcpy( (BYTE *)emr + emr->offBmi, info, emr->cbBmi );
326             get_brush_bitmap_info( brush, NULL, (char *)emr + emr->offBits, NULL );
327 
328             if (!emfdc_record( emf, &emr->emr )) index = 0;
329             HeapFree( GetProcessHeap(), 0, emr );
330         }
331         break;
332 
333     default:
334         FIXME("Unknown style %x\n", logbrush.lbStyle);
335         break;
336     }
337 
338     return index;
339 }
340 
emfdc_select_brush(WINEDC * dc_attr,HBRUSH brush)341 static BOOL emfdc_select_brush( WINEDC *dc_attr, HBRUSH brush )
342 {
343     struct emf *emf = dc_attr->emf;
344     EMRSELECTOBJECT emr;
345     DWORD index = 0;
346     int i;
347 
348     /* If the object is a stock brush object, do not need to create it.
349      * See definitions in  wingdi.h for range of stock brushes.
350      * We do however have to handle setting the higher order bit to
351      * designate that this is a stock object.
352      */
353     for (i = WHITE_BRUSH; i <= DC_BRUSH; i++)
354     {
355         if (brush == GetStockObject(i))
356         {
357             index = i | 0x80000000;
358             break;
359         }
360     }
361 
362     if (!index && !(index = emfdc_find_object( emf, brush )))
363     {
364         if (!(index = emfdc_create_brush( emf, brush ))) return 0;
365         GDI_hdc_using_object( brush, dc_attr->hdc);//, emfdc_delete_object );
366     }
367 
368     emr.emr.iType = EMR_SELECTOBJECT;
369     emr.emr.nSize = sizeof(emr);
370     emr.ihObject = index;
371     return emfdc_record( emf, &emr.emr );
372 }
373 
emfdc_create_font(struct emf * emf,HFONT font)374 static BOOL emfdc_create_font( struct emf *emf, HFONT font )
375 {
376     DWORD index = 0;
377     EMREXTCREATEFONTINDIRECTW emr;
378     int i;
379 
380     if (!GetObjectW( font, sizeof(emr.elfw.elfLogFont), &emr.elfw.elfLogFont )) return FALSE;
381 
382     emr.emr.iType = EMR_EXTCREATEFONTINDIRECTW;
383     emr.emr.nSize = (sizeof(emr) + 3) / 4 * 4;
384     emr.ihFont = index = emfdc_add_handle( emf, font );
385     emr.elfw.elfFullName[0] = '\0';
386     emr.elfw.elfStyle[0]    = '\0';
387     emr.elfw.elfVersion     = 0;
388     emr.elfw.elfStyleSize   = 0;
389     emr.elfw.elfMatch       = 0;
390     emr.elfw.elfReserved    = 0;
391     for (i = 0; i < ELF_VENDOR_SIZE; i++)
392         emr.elfw.elfVendorId[i] = 0;
393     emr.elfw.elfCulture                 = PAN_CULTURE_LATIN;
394     emr.elfw.elfPanose.bFamilyType      = PAN_NO_FIT;
395     emr.elfw.elfPanose.bSerifStyle      = PAN_NO_FIT;
396     emr.elfw.elfPanose.bWeight          = PAN_NO_FIT;
397     emr.elfw.elfPanose.bProportion      = PAN_NO_FIT;
398     emr.elfw.elfPanose.bContrast        = PAN_NO_FIT;
399     emr.elfw.elfPanose.bStrokeVariation = PAN_NO_FIT;
400     emr.elfw.elfPanose.bArmStyle        = PAN_NO_FIT;
401     emr.elfw.elfPanose.bLetterform      = PAN_NO_FIT;
402     emr.elfw.elfPanose.bMidline         = PAN_NO_FIT;
403     emr.elfw.elfPanose.bXHeight         = PAN_NO_FIT;
404 
405     return emfdc_record( emf, &emr.emr ) ? index : 0;
406 }
407 
emfdc_select_font(WINEDC * dc_attr,HFONT font)408 static BOOL emfdc_select_font( WINEDC *dc_attr, HFONT font )
409 {
410     struct emf *emf = dc_attr->emf;
411     EMRSELECTOBJECT emr;
412     DWORD index;
413     int i;
414 
415     /* If the object is a stock font object, do not need to create it.
416      * See definitions in  wingdi.h for range of stock fonts.
417      * We do however have to handle setting the higher order bit to
418      * designate that this is a stock object.
419      */
420 
421     for (i = OEM_FIXED_FONT; i <= DEFAULT_GUI_FONT; i++)
422     {
423         if (i != DEFAULT_PALETTE && font == GetStockObject(i))
424         {
425             index = i | 0x80000000;
426             goto found;
427         }
428     }
429 
430     if (!(index = emfdc_find_object( emf, font )))
431     {
432         if (!(index = emfdc_create_font( emf, font ))) return FALSE;
433         GDI_hdc_using_object( font, dc_attr->hdc);//, emfdc_delete_object );
434     }
435 
436  found:
437     emr.emr.iType = EMR_SELECTOBJECT;
438     emr.emr.nSize = sizeof(emr);
439     emr.ihObject = index;
440     return emfdc_record( emf, &emr.emr );
441 }
442 
emfdc_create_pen(struct emf * emf,HPEN hPen)443 static DWORD emfdc_create_pen( struct emf *emf, HPEN hPen )
444 {
445     EMRCREATEPEN emr;
446     DWORD index = 0;
447 
448     if (!GetObjectW( hPen, sizeof(emr.lopn), &emr.lopn ))
449     {
450         /* must be an extended pen */
451         EXTLOGPEN *elp;
452         INT size = GetObjectW( hPen, 0, NULL );
453 
454         if (!size) return 0;
455 
456         elp = HeapAlloc( GetProcessHeap(), 0, size );
457 
458         GetObjectW( hPen, size, elp );
459         /* FIXME: add support for user style pens */
460         emr.lopn.lopnStyle = elp->elpPenStyle;
461         emr.lopn.lopnWidth.x = elp->elpWidth;
462         emr.lopn.lopnWidth.y = 0;
463         emr.lopn.lopnColor = elp->elpColor;
464 
465         HeapFree( GetProcessHeap(), 0, elp );
466     }
467 
468     emr.emr.iType = EMR_CREATEPEN;
469     emr.emr.nSize = sizeof(emr);
470     emr.ihPen = index = emfdc_add_handle( emf, hPen );
471     return emfdc_record( emf, &emr.emr ) ? index : 0;
472 }
473 
emfdc_select_pen(WINEDC * dc_attr,HPEN pen)474 static BOOL emfdc_select_pen( WINEDC *dc_attr, HPEN pen )
475 {
476     struct emf *emf = dc_attr->emf;
477     EMRSELECTOBJECT emr;
478     DWORD index = 0;
479     int i;
480 
481     /* If the object is a stock pen object, do not need to create it.
482      * See definitions in  wingdi.h for range of stock pens.
483      * We do however have to handle setting the higher order bit to
484      * designate that this is a stock object.
485      */
486 
487     for (i = WHITE_PEN; i <= DC_PEN; i++)
488     {
489         if (pen == GetStockObject(i))
490         {
491             index = i | 0x80000000;
492             break;
493         }
494     }
495     if (!index && !(index = emfdc_find_object( emf, pen )))
496     {
497         if (!(index = emfdc_create_pen( emf, pen ))) return FALSE;
498         GDI_hdc_using_object( pen, dc_attr->hdc);//, emfdc_delete_object );
499     }
500 
501     emr.emr.iType = EMR_SELECTOBJECT;
502     emr.emr.nSize = sizeof(emr);
503     emr.ihObject = index;
504     return emfdc_record( emf, &emr.emr );
505 }
506 
emfdc_create_palette(struct emf * emf,HPALETTE hPal)507 static DWORD emfdc_create_palette( struct emf *emf, HPALETTE hPal )
508 {
509     WORD i;
510     struct {
511         EMRCREATEPALETTE hdr;
512         PALETTEENTRY entry[255];
513     } pal;
514 
515     memset( &pal, 0, sizeof(pal) );
516 
517     if (!GetObjectW( hPal, sizeof(pal.hdr.lgpl) + sizeof(pal.entry), &pal.hdr.lgpl ))
518         return 0;
519 
520     for (i = 0; i < pal.hdr.lgpl.palNumEntries; i++)
521         pal.hdr.lgpl.palPalEntry[i].peFlags = 0;
522 
523     pal.hdr.emr.iType = EMR_CREATEPALETTE;
524     pal.hdr.emr.nSize = sizeof(pal.hdr) + pal.hdr.lgpl.palNumEntries * sizeof(PALETTEENTRY);
525     pal.hdr.ihPal = emfdc_add_handle( emf, hPal );
526 
527     if (!emfdc_record( emf, &pal.hdr.emr ))
528         pal.hdr.ihPal = 0;
529     return pal.hdr.ihPal;
530 }
531 
EMFDC_SelectPalette(WINEDC * dc_attr,HPALETTE palette)532 BOOL EMFDC_SelectPalette( WINEDC *dc_attr, HPALETTE palette )
533 {
534     struct emf *emf = dc_attr->emf;
535     EMRSELECTPALETTE emr;
536     DWORD index = 0;
537 
538     if (palette == GetStockObject( DEFAULT_PALETTE ))
539     {
540         index = DEFAULT_PALETTE | 0x80000000;
541     }
542     else if (!(index = emfdc_find_object( emf, palette )))
543     {
544         if (!(index = emfdc_create_palette( emf, palette ))) return 0;
545         GDI_hdc_using_object( palette, dc_attr->hdc);//, emfdc_delete_object );
546     }
547 
548     emr.emr.iType = EMR_SELECTPALETTE;
549     emr.emr.nSize = sizeof(emr);
550     emr.ihPal = index;
551     return emfdc_record( emf, &emr.emr );
552 }
553 
EMFDC_SelectObject(WINEDC * dc_attr,HGDIOBJ obj)554 BOOL EMFDC_SelectObject( WINEDC *dc_attr, HGDIOBJ obj )
555 {
556     switch (GDI_HANDLE_GET_TYPE( obj ))
557     {
558     case GDILoObjType_LO_BRUSH_TYPE:
559         return emfdc_select_brush( dc_attr, obj );
560     case GDILoObjType_LO_FONT_TYPE:
561         return emfdc_select_font( dc_attr, obj );
562     case GDILoObjType_LO_PEN_TYPE:
563     case GDILoObjType_LO_EXTPEN_TYPE:
564         return emfdc_select_pen( dc_attr, obj );
565     default:
566         return TRUE;
567     }
568 }
569 
570 /* determine if we can use 16-bit points to store all the input points */
can_use_short_points(const POINT * pts,UINT count)571 static BOOL can_use_short_points( const POINT *pts, UINT count )
572 {
573     UINT i;
574 
575     for (i = 0; i < count; i++)
576         if (((pts[i].x + 0x8000) & ~0xffff) || ((pts[i].y + 0x8000) & ~0xffff))
577             return FALSE;
578     return TRUE;
579 }
580 
581 /* store points in either long or short format; return a pointer to the end of the stored data */
store_points(POINTL * dest,const POINT * pts,UINT count,BOOL short_points)582 static void *store_points( POINTL *dest, const POINT *pts, UINT count, BOOL short_points )
583 {
584     if (short_points)
585     {
586         UINT i;
587         POINTS *dest_short = (POINTS *)dest;
588 
589         for (i = 0; i < count; i++)
590         {
591             dest_short[i].x = pts[i].x;
592             dest_short[i].y = pts[i].y;
593         }
594         return dest_short + count;
595     }
596     else
597     {
598         memcpy( dest, pts, count * sizeof(*dest) );
599         return dest + count;
600     }
601 }
602 
603 /* compute the bounds of an array of points, optionally including the current position */
get_points_bounds(RECTL * bounds,const POINT * pts,UINT count,WINEDC * dc_attr)604 static void get_points_bounds( RECTL *bounds, const POINT *pts, UINT count, WINEDC *dc_attr )
605 {
606     UINT i;
607 
608     if (dc_attr)
609     {
610         POINT cur_pos;
611         GetCurrentPositionEx(dc_attr->hdc, &cur_pos);
612         bounds->left = bounds->right = cur_pos.x;
613         bounds->top = bounds->bottom = cur_pos.y;
614     }
615     else if (count)
616     {
617         bounds->left = bounds->right = pts[0].x;
618         bounds->top = bounds->bottom = pts[0].y;
619     }
620     else *bounds = empty_bounds;
621 
622     for (i = 0; i < count; i++)
623     {
624         bounds->left   = min( bounds->left, pts[i].x );
625         bounds->right  = max( bounds->right, pts[i].x );
626         bounds->top    = min( bounds->top, pts[i].y );
627         bounds->bottom = max( bounds->bottom, pts[i].y );
628     }
629 }
630 
631 /* helper for path stroke and fill functions */
632 #ifdef __REACTOS__
emfdrv_stroke_and_fill_path(struct emf * emf,INT type)633 static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type )
634 {
635     EMRSTROKEANDFILLPATH emr;
636     LPPOINT Points;
637     LPBYTE Types;
638     INT nSize;
639 
640     emr.emr.iType = type;
641     emr.emr.nSize = sizeof(emr);
642 
643     nSize = GetPath(emf->dc_attr->hdc, NULL, NULL, 0);
644     if (nSize != -1)
645     {
646        Points = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(POINT) );
647        Types  = HeapAlloc( GetProcessHeap(), 0, nSize*sizeof(BYTE) );
648 
649        GetPath(emf->dc_attr->hdc, Points, Types, nSize);
650        get_points_bounds( &emr.rclBounds, Points, nSize, 0 );
651 
652        HeapFree( GetProcessHeap(), 0, Points );
653        HeapFree( GetProcessHeap(), 0, Types );
654 
655        TRACE("GetBounds l %d t %d r %d b %d\n",emr.rclBounds.left, emr.rclBounds.top, emr.rclBounds.right, emr.rclBounds.bottom);
656     }
657     else emr.rclBounds = empty_bounds;
658 
659     if (!emfdc_record( emf, &emr.emr )) return FALSE;
660     if (nSize == -1 ) return FALSE;
661     emfdc_update_bounds( emf, &emr.rclBounds );
662     return TRUE;
663 }
664 #else
emfdrv_stroke_and_fill_path(struct emf * emf,INT type)665 static BOOL emfdrv_stroke_and_fill_path( struct emf *emf, INT type )
666 {
667     EMRSTROKEANDFILLPATH emr;
668     HRGN region;
669 
670     emr.emr.iType = type;
671     emr.emr.nSize = sizeof(emr);
672     emr.rclBounds = empty_bounds;
673 
674     if ((region = NtGdiPathToRegion( emf->dc_attr->hdc ))) // WTF are you doing? This removes path!!!
675     {
676         NtGdiGetRgnBox( region, (RECT *)&emr.rclBounds );
677         DeleteObject( region );
678     }
679     if (!emfdc_record( emf, &emr.emr )) return FALSE;
680     if (!region) return FALSE;
681     emfdc_update_bounds( emf, &emr.rclBounds );
682     return TRUE;
683 }
684 #endif
EMFDC_MoveTo(WINEDC * dc_attr,INT x,INT y)685 BOOL EMFDC_MoveTo( WINEDC *dc_attr, INT x, INT y )
686 {
687     struct emf *emf = dc_attr->emf;
688     EMRMOVETOEX emr;
689 
690     emr.emr.iType = EMR_MOVETOEX;
691     emr.emr.nSize = sizeof(emr);
692     emr.ptl.x = x;
693     emr.ptl.y = y;
694     return emfdc_record( emf, &emr.emr );
695 }
696 
EMFDC_LineTo(WINEDC * dc_attr,INT x,INT y)697 BOOL EMFDC_LineTo( WINEDC *dc_attr, INT x, INT y )
698 {
699     EMRLINETO emr;
700     BOOL Ret;
701 
702     emr.emr.iType = EMR_LINETO;
703     emr.emr.nSize = sizeof(emr);
704     emr.ptl.x = x;
705     emr.ptl.y = y;
706     Ret = emfdc_record( dc_attr->emf, &emr.emr );
707     EMFDRV_LineTo( dc_attr, x,  y );
708     return Ret;
709 }
710 
EMFDC_ArcChordPie(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend,DWORD type)711 BOOL EMFDC_ArcChordPie( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom,
712                         INT xstart, INT ystart, INT xend, INT yend, DWORD type )
713 {
714     struct emf *emf = dc_attr->emf;
715     EMRARC emr;
716     INT temp;
717     BOOL Ret;
718 
719     if (left == right || top == bottom) return FALSE;
720 
721     if (left > right) { temp = left; left = right; right = temp; }
722     if (top > bottom) { temp = top; top = bottom; bottom = temp; }
723 
724     if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
725     {
726         right--;
727         bottom--;
728     }
729 
730     emr.emr.iType     = type;
731     emr.emr.nSize     = sizeof(emr);
732     emr.rclBox.left   = left;
733     emr.rclBox.top    = top;
734     emr.rclBox.right  = right;
735     emr.rclBox.bottom = bottom;
736     emr.ptlStart.x    = xstart;
737     emr.ptlStart.y    = ystart;
738     emr.ptlEnd.x      = xend;
739     emr.ptlEnd.y      = yend;
740     Ret = emfdc_record( emf, &emr.emr );
741     EMFDRV_ArcChordPie( dc_attr, left, top, right, bottom, xstart, ystart, xend, yend, type );
742     return Ret;
743 }
744 
EMFDC_AngleArc(WINEDC * dc_attr,INT x,INT y,DWORD radius,FLOAT start,FLOAT sweep)745 BOOL EMFDC_AngleArc( WINEDC *dc_attr, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
746 {
747     EMRANGLEARC emr;
748 
749     emr.emr.iType   = EMR_ANGLEARC;
750     emr.emr.nSize   = sizeof( emr );
751     emr.ptlCenter.x = x;
752     emr.ptlCenter.y = y;
753     emr.nRadius     = radius;
754     emr.eStartAngle = start;
755     emr.eSweepAngle = sweep;
756     return emfdc_record( dc_attr->emf, &emr.emr );
757 }
758 
EMFDC_Ellipse(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom)759 BOOL EMFDC_Ellipse( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
760 {
761     struct emf *emf = dc_attr->emf;
762     EMRELLIPSE emr;
763     BOOL Ret;
764 
765     if (left == right || top == bottom) return FALSE;
766 
767     emr.emr.iType     = EMR_ELLIPSE;
768     emr.emr.nSize     = sizeof(emr);
769     emr.rclBox.left   = min( left, right );
770     emr.rclBox.top    = min( top, bottom );
771     emr.rclBox.right  = max( left, right );
772     emr.rclBox.bottom = max( top, bottom );
773     if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
774     {
775         emr.rclBox.right--;
776         emr.rclBox.bottom--;
777     }
778     Ret = emfdc_record( emf, &emr.emr );
779     EMFDRV_Ellipse( dc_attr, left, top, right, bottom );
780     return Ret;
781 }
782 
EMFDC_Rectangle(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom)783 BOOL EMFDC_Rectangle( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
784 {
785     struct emf *emf = dc_attr->emf;
786     EMRRECTANGLE emr;
787     BOOL Ret;
788 
789     if(left == right || top == bottom) return FALSE;
790 
791     emr.emr.iType     = EMR_RECTANGLE;
792     emr.emr.nSize     = sizeof(emr);
793     emr.rclBox.left   = min( left, right );
794     emr.rclBox.top    = min( top, bottom );
795     emr.rclBox.right  = max( left, right );
796     emr.rclBox.bottom = max( top, bottom );
797     if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
798     {
799         emr.rclBox.right--;
800         emr.rclBox.bottom--;
801     }
802     Ret = emfdc_record( emf, &emr.emr );
803     EMFDRV_Rectangle( dc_attr, left, top, right, bottom );
804     return Ret;
805 }
806 
EMFDC_RoundRect(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom,INT ell_width,INT ell_height)807 BOOL EMFDC_RoundRect( WINEDC *dc_attr, INT left, INT top, INT right,
808                       INT bottom, INT ell_width, INT ell_height )
809 {
810     struct emf *emf = dc_attr->emf;
811     EMRROUNDRECT emr;
812     BOOL Ret;
813 
814     if (left == right || top == bottom) return FALSE;
815 
816     emr.emr.iType     = EMR_ROUNDRECT;
817     emr.emr.nSize     = sizeof(emr);
818     emr.rclBox.left   = min( left, right );
819     emr.rclBox.top    = min( top, bottom );
820     emr.rclBox.right  = max( left, right );
821     emr.rclBox.bottom = max( top, bottom );
822     emr.szlCorner.cx  = ell_width;
823     emr.szlCorner.cy  = ell_height;
824     if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
825     {
826         emr.rclBox.right--;
827         emr.rclBox.bottom--;
828     }
829     Ret = emfdc_record( emf, &emr.emr );
830     EMFDRV_RoundRect( dc_attr, left, top, right, bottom, ell_width, ell_height );
831     return Ret;
832 }
833 
EMFDC_SetPixel(WINEDC * dc_attr,INT x,INT y,COLORREF color)834 BOOL EMFDC_SetPixel( WINEDC *dc_attr, INT x, INT y, COLORREF color )
835 {
836     EMRSETPIXELV emr;
837     BOOL Ret;
838 
839     emr.emr.iType  = EMR_SETPIXELV;
840     emr.emr.nSize  = sizeof(emr);
841     emr.ptlPixel.x = x;
842     emr.ptlPixel.y = y;
843     emr.crColor = color;
844     Ret = emfdc_record( dc_attr->emf, &emr.emr );
845     EMFDRV_SetPixel( dc_attr, x, y, color );
846     return Ret;
847 }
848 
emfdc_polylinegon(WINEDC * dc_attr,const POINT * points,INT count,DWORD type)849 static BOOL emfdc_polylinegon( WINEDC *dc_attr, const POINT *points, INT count, DWORD type )
850 {
851     struct emf *emf = dc_attr->emf;
852     EMRPOLYLINE *emr;
853     DWORD size;
854     BOOL ret, use_small_emr = can_use_short_points( points, count );
855 
856     size = use_small_emr ? (DWORD)offsetof( EMRPOLYLINE16, apts[count] ) : (DWORD)offsetof( EMRPOLYLINE, aptl[count] );
857 
858     emr = HeapAlloc( GetProcessHeap(), 0, size );
859     emr->emr.iType = use_small_emr ? type + EMR_POLYLINE16 - EMR_POLYLINE : type;
860     emr->emr.nSize = size;
861     emr->cptl = count;
862 
863     store_points( emr->aptl, points, count, use_small_emr );
864 
865     if (!emf->path)
866         get_points_bounds( &emr->rclBounds, points, count,
867                            (type == EMR_POLYBEZIERTO || type == EMR_POLYLINETO) ? dc_attr : 0 );
868     else
869         emr->rclBounds = empty_bounds;
870 
871     ret = emfdc_record( emf, &emr->emr );
872     if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
873     HeapFree( GetProcessHeap(), 0, emr );
874     return ret;
875 }
876 
EMFDC_Polyline(WINEDC * dc_attr,const POINT * points,INT count)877 BOOL EMFDC_Polyline( WINEDC *dc_attr, const POINT *points, INT count )
878 {
879     return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINE );
880 }
881 
EMFDC_PolylineTo(WINEDC * dc_attr,const POINT * points,INT count)882 BOOL EMFDC_PolylineTo( WINEDC *dc_attr, const POINT *points, INT count )
883 {
884     return emfdc_polylinegon( dc_attr, points, count, EMR_POLYLINETO );
885 }
886 
EMFDC_Polygon(WINEDC * dc_attr,const POINT * pt,INT count)887 BOOL EMFDC_Polygon( WINEDC *dc_attr, const POINT *pt, INT count )
888 {
889     if(count < 2) return FALSE;
890     return emfdc_polylinegon( dc_attr, pt, count, EMR_POLYGON );
891 }
892 
EMFDC_PolyBezier(WINEDC * dc_attr,const POINT * pts,DWORD count)893 BOOL EMFDC_PolyBezier( WINEDC *dc_attr, const POINT *pts, DWORD count )
894 {
895     return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIER );
896 }
897 
EMFDC_PolyBezierTo(WINEDC * dc_attr,const POINT * pts,DWORD count)898 BOOL EMFDC_PolyBezierTo( WINEDC *dc_attr, const POINT *pts, DWORD count )
899 {
900     return emfdc_polylinegon( dc_attr, pts, count, EMR_POLYBEZIERTO );
901 }
902 
emfdc_poly_polylinegon(struct emf * emf,const POINT * pt,const INT * counts,UINT polys,DWORD type)903 static BOOL emfdc_poly_polylinegon( struct emf *emf, const POINT *pt, const INT *counts,
904                                    UINT polys, DWORD type)
905 {
906     EMRPOLYPOLYLINE *emr;
907     DWORD cptl = 0, poly, size;
908     BOOL ret, use_small_emr, bounds_valid = TRUE;
909 
910     for(poly = 0; poly < polys; poly++) {
911         cptl += counts[poly];
912         if(counts[poly] < 2) bounds_valid = FALSE;
913     }
914     if(!cptl) bounds_valid = FALSE;
915     use_small_emr = can_use_short_points( pt, cptl );
916 
917     size = FIELD_OFFSET(EMRPOLYPOLYLINE, aPolyCounts[polys]);
918     if(use_small_emr)
919         size += cptl * sizeof(POINTS);
920     else
921         size += cptl * sizeof(POINTL);
922 
923     emr = HeapAlloc( GetProcessHeap(), 0, size );
924 
925     emr->emr.iType = type;
926     if(use_small_emr) emr->emr.iType += EMR_POLYPOLYLINE16 - EMR_POLYPOLYLINE;
927 
928     emr->emr.nSize = size;
929     if(bounds_valid && !emf->path)
930         get_points_bounds( &emr->rclBounds, pt, cptl, 0 );
931     else
932         emr->rclBounds = empty_bounds;
933     emr->nPolys = polys;
934     emr->cptl = cptl;
935 
936     if(polys)
937     {
938         memcpy( emr->aPolyCounts, counts, polys * sizeof(DWORD) );
939         store_points( (POINTL *)(emr->aPolyCounts + polys), pt, cptl, use_small_emr );
940     }
941 
942     ret = emfdc_record( emf, &emr->emr );
943     if(ret && !bounds_valid)
944     {
945         ret = FALSE;
946         SetLastError( ERROR_INVALID_PARAMETER );
947     }
948     if(ret && !emf->path)
949         emfdc_update_bounds( emf, &emr->rclBounds );
950     HeapFree( GetProcessHeap(), 0, emr );
951     return ret;
952 }
953 
EMFDC_PolyPolyline(WINEDC * dc_attr,const POINT * pt,const DWORD * counts,DWORD polys)954 BOOL EMFDC_PolyPolyline( WINEDC *dc_attr, const POINT *pt, const DWORD *counts, DWORD polys)
955 {
956     return emfdc_poly_polylinegon( dc_attr->emf, pt, (const INT *)counts, polys, EMR_POLYPOLYLINE );
957 }
958 
EMFDC_PolyPolygon(WINEDC * dc_attr,const POINT * pt,const INT * counts,UINT polys)959 BOOL EMFDC_PolyPolygon( WINEDC *dc_attr, const POINT *pt, const INT *counts, UINT polys )
960 {
961     return emfdc_poly_polylinegon( dc_attr->emf, pt, counts, polys, EMR_POLYPOLYGON );
962 }
963 
EMFDC_PolyDraw(WINEDC * dc_attr,const POINT * pts,const BYTE * types,DWORD count)964 BOOL EMFDC_PolyDraw( WINEDC *dc_attr, const POINT *pts, const BYTE *types, DWORD count )
965 {
966     struct emf *emf = dc_attr->emf;
967     EMRPOLYDRAW *emr;
968     BOOL ret;
969     BYTE *types_dest;
970     BOOL use_small_emr = can_use_short_points( pts, count );
971     DWORD size;
972 
973     size = use_small_emr ? (DWORD)offsetof( EMRPOLYDRAW16, apts[count] )
974         : (DWORD)offsetof( EMRPOLYDRAW, aptl[count] );
975     size += (count + 3) & ~3;
976 
977     if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
978 
979     emr->emr.iType = use_small_emr ? EMR_POLYDRAW16 : EMR_POLYDRAW;
980     emr->emr.nSize = size;
981     emr->cptl = count;
982 
983     types_dest = store_points( emr->aptl, pts, count, use_small_emr );
984     memcpy( types_dest, types, count );
985     if (count & 3) memset( types_dest + count, 0, 4 - (count & 3) );
986 
987     if (!emf->path)
988         get_points_bounds( &emr->rclBounds, pts, count, 0 );
989     else
990         emr->rclBounds = empty_bounds;
991 
992     ret = emfdc_record( emf, &emr->emr );
993     if (ret && !emf->path) emfdc_update_bounds( emf, &emr->rclBounds );
994     HeapFree( GetProcessHeap(), 0, emr );
995     return ret;
996 }
997 
EMFDC_ExtFloodFill(WINEDC * dc_attr,INT x,INT y,COLORREF color,UINT fill_type)998 BOOL EMFDC_ExtFloodFill( WINEDC *dc_attr, INT x, INT y, COLORREF color, UINT fill_type )
999 {
1000     EMREXTFLOODFILL emr;
1001 
1002     emr.emr.iType = EMR_EXTFLOODFILL;
1003     emr.emr.nSize = sizeof(emr);
1004     emr.ptlStart.x = x;
1005     emr.ptlStart.y = y;
1006     emr.crColor = color;
1007     emr.iMode = fill_type;
1008     return emfdc_record( dc_attr->emf, &emr.emr );
1009 }
1010 
EMFDC_FillRgn(WINEDC * dc_attr,HRGN hrgn,HBRUSH hbrush)1011 BOOL EMFDC_FillRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush )
1012 {
1013     struct emf *emf = dc_attr->emf;
1014     EMRFILLRGN *emr;
1015     DWORD size, rgnsize, index;
1016     BOOL ret;
1017 
1018     if (!(index = emfdc_create_brush( emf, hbrush ))) return FALSE;
1019 
1020     rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
1021     size = rgnsize + offsetof(EMRFILLRGN,RgnData);
1022     emr = HeapAlloc( GetProcessHeap(), 0, size );
1023 
1024     /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1025 
1026     emr->emr.iType = EMR_FILLRGN;
1027     emr->emr.nSize = size;
1028     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1029     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1030     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1031     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1032     emr->cbRgnData = rgnsize;
1033     emr->ihBrush = index;
1034 
1035     ret = emfdc_record( emf, &emr->emr );
1036     if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1037     HeapFree( GetProcessHeap(), 0, emr );
1038     return ret;
1039 }
1040 
EMFDC_FrameRgn(WINEDC * dc_attr,HRGN hrgn,HBRUSH hbrush,INT width,INT height)1041 BOOL EMFDC_FrameRgn( WINEDC *dc_attr, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
1042 {
1043     struct emf *emf = dc_attr->emf;
1044     EMRFRAMERGN *emr;
1045     DWORD size, rgnsize, index;
1046     BOOL ret;
1047 
1048     index = emfdc_create_brush( emf, hbrush );
1049     if(!index) return FALSE;
1050 
1051     rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
1052     size = rgnsize + offsetof(EMRFRAMERGN,RgnData);
1053     emr = HeapAlloc( GetProcessHeap(), 0, size );
1054 
1055     /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1056 
1057     emr->emr.iType = EMR_FRAMERGN;
1058     emr->emr.nSize = size;
1059     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1060     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1061     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1062     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1063     emr->cbRgnData = rgnsize;
1064     emr->ihBrush = index;
1065     emr->szlStroke.cx = width;
1066     emr->szlStroke.cy = height;
1067 
1068     ret = emfdc_record( emf, &emr->emr );
1069     if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1070     HeapFree( GetProcessHeap(), 0, emr );
1071     return ret;
1072 }
1073 
emfdc_paint_invert_region(struct emf * emf,HRGN hrgn,DWORD iType)1074 static BOOL emfdc_paint_invert_region( struct emf *emf, HRGN hrgn, DWORD iType )
1075 {
1076     EMRINVERTRGN *emr;
1077     DWORD size, rgnsize;
1078     BOOL ret;
1079 
1080     rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
1081     size = rgnsize + offsetof(EMRINVERTRGN,RgnData);
1082     emr = HeapAlloc( GetProcessHeap(), 0, size );
1083 
1084     /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
1085 
1086     emr->emr.iType = iType;
1087     emr->emr.nSize = size;
1088     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
1089     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
1090     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
1091     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
1092     emr->cbRgnData = rgnsize;
1093 
1094     ret = emfdc_record( emf, &emr->emr );
1095     if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1096     HeapFree( GetProcessHeap(), 0, emr );
1097     return ret;
1098 }
1099 
EMFDC_PaintRgn(WINEDC * dc_attr,HRGN hrgn)1100 BOOL EMFDC_PaintRgn( WINEDC *dc_attr, HRGN hrgn )
1101 {
1102     return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_PAINTRGN );
1103 }
1104 
EMFDC_InvertRgn(WINEDC * dc_attr,HRGN hrgn)1105 BOOL EMFDC_InvertRgn( WINEDC *dc_attr, HRGN hrgn )
1106 {
1107     return emfdc_paint_invert_region( dc_attr->emf, hrgn, EMR_INVERTRGN );
1108 }
1109 
EMFDC_ExtTextOut(WINEDC * dc_attr,INT x,INT y,UINT flags,const RECT * rect,const WCHAR * str,UINT count,const INT * dx)1110 BOOL EMFDC_ExtTextOut( WINEDC *dc_attr, INT x, INT y, UINT flags, const RECT *rect,
1111                        const WCHAR *str, UINT count, const INT *dx )
1112 {
1113     struct emf *emf = dc_attr->emf;
1114     FLOAT ex_scale, ey_scale;
1115     EMREXTTEXTOUTW *emr;
1116     int text_height = 0;
1117     int text_width = 0;
1118     TEXTMETRICW tm;
1119     DWORD size;
1120     BOOL ret;
1121 
1122     if (count > INT_MAX) return FALSE;
1123 
1124     size = sizeof(*emr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
1125 
1126     TRACE( "%s %s count %d size = %d\n", debugstr_wn(str, count),
1127            wine_dbgstr_rect(rect), count, size );
1128     emr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
1129 
1130     if (GetGraphicsMode(dc_attr->hdc) == GM_COMPATIBLE)
1131     {
1132         const INT horzSize = GetDeviceCaps( dc_attr->hdc, HORZSIZE );
1133         const INT horzRes  = GetDeviceCaps( dc_attr->hdc, HORZRES );
1134         const INT vertSize = GetDeviceCaps( dc_attr->hdc, VERTSIZE );
1135         const INT vertRes  = GetDeviceCaps( dc_attr->hdc, VERTRES );
1136         SIZE wndext, vportext;
1137 
1138         GetViewportExtEx( dc_attr->hdc, &vportext );
1139         GetWindowExtEx( dc_attr->hdc, &wndext );
1140         ex_scale = 100.0 * ((FLOAT)horzSize  / (FLOAT)horzRes) /
1141             ((FLOAT)wndext.cx / (FLOAT)vportext.cx);
1142         ey_scale = 100.0 * ((FLOAT)vertSize  / (FLOAT)vertRes) /
1143             ((FLOAT)wndext.cy / (FLOAT)vportext.cy);
1144     }
1145     else
1146     {
1147         ex_scale = 0.0;
1148         ey_scale = 0.0;
1149     }
1150 
1151     emr->emr.iType = EMR_EXTTEXTOUTW;
1152     emr->emr.nSize = size;
1153     emr->iGraphicsMode = GetGraphicsMode(dc_attr->hdc);
1154     emr->exScale = ex_scale;
1155     emr->eyScale = ey_scale;
1156     emr->emrtext.ptlReference.x = x;
1157     emr->emrtext.ptlReference.y = y;
1158     emr->emrtext.nChars = count;
1159     emr->emrtext.offString = sizeof(*emr);
1160     memcpy( (char*)emr + emr->emrtext.offString, str, count * sizeof(WCHAR) );
1161     emr->emrtext.fOptions = flags;
1162     if (!rect)
1163     {
1164         emr->emrtext.rcl.left = emr->emrtext.rcl.top = 0;
1165         emr->emrtext.rcl.right = emr->emrtext.rcl.bottom = -1;
1166     }
1167     else
1168     {
1169         emr->emrtext.rcl.left = rect->left;
1170         emr->emrtext.rcl.top = rect->top;
1171         emr->emrtext.rcl.right = rect->right;
1172         emr->emrtext.rcl.bottom = rect->bottom;
1173     }
1174 
1175     emr->emrtext.offDx = emr->emrtext.offString + ((count+1) & ~1) * sizeof(WCHAR);
1176     if (dx)
1177     {
1178         UINT i;
1179         SIZE str_size;
1180         memcpy( (char*)emr + emr->emrtext.offDx, dx, count * sizeof(INT) );
1181         for (i = 0; i < count; i++) text_width += dx[i];
1182         if (GetTextExtentPoint32W( dc_attr->hdc, str, count, &str_size ))
1183             text_height = str_size.cy;
1184     }
1185     else
1186     {
1187         UINT i;
1188         INT *emf_dx = (INT *)((char*)emr + emr->emrtext.offDx);
1189         SIZE charSize;
1190         for (i = 0; i < count; i++)
1191         {
1192             if (GetTextExtentPoint32W( dc_attr->hdc, str + i, 1, &charSize ))
1193             {
1194                 emf_dx[i] = charSize.cx;
1195                 text_width += charSize.cx;
1196                 text_height = max( text_height, charSize.cy );
1197             }
1198         }
1199     }
1200 
1201     if (emf->path)
1202     {
1203         emr->rclBounds.left = emr->rclBounds.top = 0;
1204         emr->rclBounds.right = emr->rclBounds.bottom = -1;
1205         goto no_bounds;
1206     }
1207 
1208     /* FIXME: handle font escapement */
1209     switch (GetTextAlign(dc_attr->hdc) & (TA_LEFT | TA_RIGHT | TA_CENTER))
1210     {
1211     case TA_CENTER:
1212         emr->rclBounds.left  = x - (text_width / 2) - 1;
1213         emr->rclBounds.right = x + (text_width / 2) + 1;
1214         break;
1215 
1216     case TA_RIGHT:
1217         emr->rclBounds.left  = x - text_width - 1;
1218         emr->rclBounds.right = x;
1219         break;
1220 
1221     default: /* TA_LEFT */
1222         emr->rclBounds.left  = x;
1223         emr->rclBounds.right = x + text_width + 1;
1224     }
1225 
1226     switch (GetTextAlign(dc_attr->hdc) & (TA_TOP | TA_BOTTOM | TA_BASELINE))
1227     {
1228     case TA_BASELINE:
1229         if (!GetTextMetricsW( dc_attr->hdc, &tm )) tm.tmDescent = 0;
1230         /* Play safe here... it's better to have a bounding box */
1231         /* that is too big than too small. */
1232         emr->rclBounds.top    = y - text_height - 1;
1233         emr->rclBounds.bottom = y + tm.tmDescent + 1;
1234         break;
1235 
1236     case TA_BOTTOM:
1237         emr->rclBounds.top    = y - text_height - 1;
1238         emr->rclBounds.bottom = y;
1239         break;
1240 
1241     default: /* TA_TOP */
1242         emr->rclBounds.top    = y;
1243         emr->rclBounds.bottom = y + text_height + 1;
1244     }
1245     emfdc_update_bounds( emf, &emr->rclBounds );
1246 
1247 no_bounds:
1248     ret = emfdc_record( emf, &emr->emr );
1249     HeapFree( GetProcessHeap(), 0, emr );
1250     return ret;
1251 }
1252 
EMFDC_GradientFill(WINEDC * dc_attr,TRIVERTEX * vert_array,ULONG nvert,void * grad_array,ULONG ngrad,ULONG mode)1253 BOOL EMFDC_GradientFill( WINEDC *dc_attr, TRIVERTEX *vert_array, ULONG nvert,
1254                          void *grad_array, ULONG ngrad, ULONG mode )
1255 {
1256     EMRGRADIENTFILL *emr;
1257     ULONG i, pt, size, num_pts = ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2);
1258     const ULONG *pts = (const ULONG *)grad_array;
1259     BOOL ret;
1260 
1261     size = FIELD_OFFSET(EMRGRADIENTFILL, Ver[nvert]) + num_pts * sizeof(pts[0]);
1262 
1263     emr = HeapAlloc( GetProcessHeap(), 0, size );
1264     if (!emr) return FALSE;
1265 
1266     for (i = 0; i < num_pts; i++)
1267     {
1268         pt = pts[i];
1269 
1270         if (i == 0)
1271         {
1272             emr->rclBounds.left = emr->rclBounds.right = vert_array[pt].x;
1273             emr->rclBounds.top = emr->rclBounds.bottom = vert_array[pt].y;
1274         }
1275         else
1276         {
1277             if (vert_array[pt].x < emr->rclBounds.left)
1278                 emr->rclBounds.left = vert_array[pt].x;
1279             else if (vert_array[pt].x > emr->rclBounds.right)
1280                 emr->rclBounds.right = vert_array[pt].x;
1281             if (vert_array[pt].y < emr->rclBounds.top)
1282                 emr->rclBounds.top = vert_array[pt].y;
1283             else if (vert_array[pt].y > emr->rclBounds.bottom)
1284                 emr->rclBounds.bottom = vert_array[pt].y;
1285         }
1286     }
1287     emr->rclBounds.right--;
1288     emr->rclBounds.bottom--;
1289 
1290     emr->emr.iType = EMR_GRADIENTFILL;
1291     emr->emr.nSize = size;
1292     emr->nVer = nvert;
1293     emr->nTri = ngrad;
1294     emr->ulMode = mode;
1295     memcpy( emr->Ver, vert_array, nvert * sizeof(vert_array[0]) );
1296     memcpy( emr->Ver + nvert, pts, num_pts * sizeof(pts[0]) );
1297 
1298     emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1299     ret = emfdc_record( dc_attr->emf, &emr->emr );
1300     HeapFree( GetProcessHeap(), 0, emr );
1301     return ret;
1302 }
1303 
EMFDC_FillPath(WINEDC * dc_attr)1304 BOOL EMFDC_FillPath( WINEDC *dc_attr )
1305 {
1306     return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_FILLPATH );
1307 }
1308 
EMFDC_StrokeAndFillPath(WINEDC * dc_attr)1309 BOOL EMFDC_StrokeAndFillPath( WINEDC *dc_attr )
1310 {
1311     return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEANDFILLPATH );
1312 }
1313 
EMFDC_StrokePath(WINEDC * dc_attr)1314 BOOL EMFDC_StrokePath( WINEDC *dc_attr )
1315 {
1316     return emfdrv_stroke_and_fill_path( dc_attr->emf, EMR_STROKEPATH );
1317 }
1318 
1319 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
emfdrv_stretchblt(struct emf * emf,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,INT width_src,INT height_src,DWORD rop,DWORD type)1320 static BOOL emfdrv_stretchblt( struct emf *emf, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1321                                HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1322                                DWORD rop, DWORD type )
1323 {
1324     BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1325     UINT bmi_size, emr_size, size;
1326     HBITMAP bitmap, blit_bitmap = NULL;
1327     EMRBITBLT *emr = NULL;
1328     BITMAPINFO *bmi;
1329     HDC blit_dc;
1330     BOOL ret = FALSE;
1331 
1332     if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
1333     {
1334         WINEDC * pldc = get_dc_ptr(hdc_src);
1335 
1336         if (pldc->iType == LDC_EMFLDC)
1337         {
1338             return FALSE;
1339         }
1340     }
1341 
1342     if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1343 
1344     blit_dc = hdc_src;
1345     blit_bitmap = bitmap;
1346     if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1347 
1348     /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1349     emr_size = type == EMR_BITBLT ? sizeof(EMRBITBLT) : sizeof(EMRSTRETCHBLT);
1350     size = emr_size + bmi_size + src_info.bmiHeader.biSizeImage;
1351 
1352     if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1353 
1354     emr->emr.iType = type;
1355     emr->emr.nSize = size;
1356     emr->rclBounds.left = x_dst;
1357     emr->rclBounds.top = y_dst;
1358     emr->rclBounds.right = x_dst + width_dst - 1;
1359     emr->rclBounds.bottom = y_dst + height_dst - 1;
1360     emr->xDest = x_dst;
1361     emr->yDest = y_dst;
1362     emr->cxDest = width_dst;
1363     emr->cyDest = height_dst;
1364     emr->xSrc = x_src;
1365     emr->ySrc = y_src;
1366     if (type != EMR_BITBLT)
1367     {
1368         EMRSTRETCHBLT *emr_stretchblt = (EMRSTRETCHBLT *)emr;
1369         emr_stretchblt->cxSrc = width_src;
1370         emr_stretchblt->cySrc = height_src;
1371     }
1372     emr->dwRop = rop;
1373     NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
1374     emr->crBkColorSrc = GetBkColor( hdc_src );
1375     emr->iUsageSrc = DIB_RGB_COLORS;
1376     emr->offBmiSrc = emr_size;
1377     emr->cbBmiSrc = bmi_size;
1378     emr->offBitsSrc = emr_size + bmi_size;
1379     emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1380 
1381     bmi = (BITMAPINFO *)((BYTE *)emr + emr->offBmiSrc);
1382     bmi->bmiHeader = src_info.bmiHeader;
1383     ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1384                      (BYTE *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1385 
1386     if (ret)
1387     {
1388         ret = emfdc_record( emf, (EMR *)emr );
1389         if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1390     }
1391 
1392 err:
1393     HeapFree( GetProcessHeap(), 0, emr );
1394     if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1395     if (blit_dc != hdc_src) DeleteDC( blit_dc );
1396     return ret;
1397 }
1398 
EMFDC_AlphaBlend(WINEDC * dc_attr,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,INT width_src,INT height_src,BLENDFUNCTION blend_function)1399 BOOL EMFDC_AlphaBlend( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1400                        HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1401                        BLENDFUNCTION blend_function )
1402 {
1403     return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst, hdc_src,
1404                               x_src, y_src, width_src, height_src, *(DWORD *)&blend_function,
1405                               EMR_ALPHABLEND );
1406 }
1407 
EMFDC_PatBlt(WINEDC * dc_attr,INT left,INT top,INT width,INT height,DWORD rop)1408 BOOL EMFDC_PatBlt( WINEDC *dc_attr, INT left, INT top, INT width, INT height, DWORD rop )
1409 {
1410     struct emf *emf = dc_attr->emf;
1411     EMRBITBLT emr;
1412     BOOL ret;
1413 
1414     emr.emr.iType = EMR_BITBLT;
1415     emr.emr.nSize = sizeof(emr);
1416     emr.rclBounds.left = left;
1417     emr.rclBounds.top = top;
1418     emr.rclBounds.right = left + width - 1;
1419     emr.rclBounds.bottom = top + height - 1;
1420     emr.xDest = left;
1421     emr.yDest = top;
1422     emr.cxDest = width;
1423     emr.cyDest = height;
1424     emr.dwRop = rop;
1425     emr.xSrc = 0;
1426     emr.ySrc = 0;
1427     emr.xformSrc.eM11 = 1.0;
1428     emr.xformSrc.eM12 = 0.0;
1429     emr.xformSrc.eM21 = 0.0;
1430     emr.xformSrc.eM22 = 1.0;
1431     emr.xformSrc.eDx = 0.0;
1432     emr.xformSrc.eDy = 0.0;
1433     emr.crBkColorSrc = 0;
1434     emr.iUsageSrc = 0;
1435     emr.offBmiSrc = 0;
1436     emr.cbBmiSrc = 0;
1437     emr.offBitsSrc = 0;
1438     emr.cbBitsSrc = 0;
1439 
1440     ret = emfdc_record( emf, &emr.emr );
1441     if (ret) emfdc_update_bounds( emf, &emr.rclBounds );
1442     return ret;
1443 }
1444 
rop_uses_src(DWORD rop)1445 static inline BOOL rop_uses_src( DWORD rop )
1446 {
1447     return ((rop >> 2) & 0x330000) != (rop & 0x330000);
1448 }
1449 
EMFDC_BitBlt(WINEDC * dc_attr,INT x_dst,INT y_dst,INT width,INT height,HDC hdc_src,INT x_src,INT y_src,DWORD rop)1450 BOOL EMFDC_BitBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width, INT height,
1451                    HDC hdc_src, INT x_src, INT y_src, DWORD rop )
1452 {
1453     if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width, height, rop );
1454     return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width, height,
1455                               hdc_src, x_src, y_src, width, height, rop, EMR_BITBLT );
1456 }
1457 
EMFDC_StretchBlt(WINEDC * dc_attr,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,INT width_src,INT height_src,DWORD rop)1458 BOOL EMFDC_StretchBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1459                        HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
1460                        DWORD rop )
1461 {
1462     if (!rop_uses_src( rop )) return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
1463     return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
1464                               hdc_src, x_src, y_src, width_src,
1465                               height_src, rop, EMR_STRETCHBLT );
1466 }
1467 
EMFDC_TransparentBlt(WINEDC * dc_attr,int x_dst,int y_dst,int width_dst,int height_dst,HDC hdc_src,int x_src,int y_src,int width_src,int height_src,UINT color)1468 BOOL EMFDC_TransparentBlt( WINEDC *dc_attr, int x_dst, int y_dst, int width_dst, int height_dst,
1469                            HDC hdc_src, int x_src, int y_src, int width_src, int height_src,
1470                            UINT color )
1471 {
1472     return emfdrv_stretchblt( dc_attr->emf, x_dst, y_dst, width_dst, height_dst,
1473                               hdc_src, x_src, y_src, width_src,
1474                               height_src, color, EMR_TRANSPARENTBLT );
1475 }
1476 
EMFDC_MaskBlt(WINEDC * dc_attr,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,HBITMAP mask,INT x_mask,INT y_mask,DWORD rop)1477 BOOL EMFDC_MaskBlt( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1478                     HDC hdc_src, INT x_src, INT y_src, HBITMAP mask,
1479                     INT x_mask, INT y_mask, DWORD rop )
1480 {
1481     unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors)
1482                            + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)];
1483     BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
1484     struct emf *emf = dc_attr->emf;
1485     BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
1486     BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1487     HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
1488     UINT bmi_size, size, mask_info_size = 0;
1489     EMRMASKBLT *emr = NULL;
1490     BITMAPINFO *bmi;
1491     HDC blit_dc, mask_dc = NULL;
1492     BOOL ret = FALSE;
1493 
1494     if (!rop_uses_src( rop ))
1495         return EMFDC_PatBlt( dc_attr, x_dst, y_dst, width_dst, height_dst, rop );
1496 
1497     if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
1498     {
1499         WINEDC * pldc = get_dc_ptr(hdc_src);
1500 
1501         if (pldc->iType == LDC_EMFLDC)
1502         {
1503             return FALSE;
1504         }
1505     }
1506 
1507     if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1508     blit_dc = hdc_src;
1509     blit_bitmap = bitmap;
1510     if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1511 
1512     if (mask)
1513     {
1514         mask_dc = hdc_src;
1515         mask_bitmap = mask;
1516         if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
1517         if (mask_info.bmiHeader.biBitCount == 1)
1518             mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
1519     }
1520     else mask_info.bmiHeader.biSizeImage = 0;
1521 
1522     size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
1523         mask_info_size + mask_info.bmiHeader.biSizeImage;
1524 
1525     if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1526 
1527     emr->emr.iType = EMR_MASKBLT;
1528     emr->emr.nSize = size;
1529     emr->rclBounds.left = x_dst;
1530     emr->rclBounds.top = y_dst;
1531     emr->rclBounds.right = x_dst + width_dst - 1;
1532     emr->rclBounds.bottom = y_dst + height_dst - 1;
1533     emr->xDest = x_dst;
1534     emr->yDest = y_dst;
1535     emr->cxDest = width_dst;
1536     emr->cyDest = height_dst;
1537     emr->dwRop = rop;
1538     emr->xSrc = x_src;
1539     emr->ySrc = y_src;
1540     NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
1541     emr->crBkColorSrc = GetBkColor( hdc_src );
1542     emr->iUsageSrc = DIB_RGB_COLORS;
1543     emr->offBmiSrc = sizeof(*emr);
1544     emr->cbBmiSrc = bmi_size;
1545     emr->offBitsSrc = emr->offBmiSrc + bmi_size;
1546     emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1547     emr->xMask = x_mask;
1548     emr->yMask = y_mask;
1549     emr->iUsageMask = DIB_PAL_MONO;
1550     emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
1551     emr->cbBmiMask = mask_info_size;
1552     emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
1553     emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
1554 
1555     bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
1556     bmi->bmiHeader = src_info.bmiHeader;
1557     ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1558                      (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1559     if (!ret) goto err;
1560 
1561     if (mask_info_size)
1562     {
1563         mask_bits_info->bmiHeader = mask_info.bmiHeader;
1564         ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
1565                          (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
1566         if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
1567     }
1568 
1569     if (ret)
1570     {
1571         ret = emfdc_record( emf, (EMR *)emr );
1572         if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1573     }
1574 
1575 err:
1576     HeapFree( GetProcessHeap(), 0, emr );
1577     if (mask_bitmap != mask) DeleteObject( mask_bitmap );
1578     if (mask_dc != hdc_src) DeleteObject( mask_dc );
1579     if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1580     if (blit_dc != hdc_src) DeleteDC( blit_dc );
1581     return ret;
1582 }
1583 
EMFDC_PlgBlt(WINEDC * dc_attr,const POINT * points,HDC hdc_src,INT x_src,INT y_src,INT width,INT height,HBITMAP mask,INT x_mask,INT y_mask)1584 BOOL EMFDC_PlgBlt( WINEDC *dc_attr, const POINT *points, HDC hdc_src, INT x_src, INT y_src,
1585                    INT width, INT height, HBITMAP mask, INT x_mask, INT y_mask )
1586 {
1587     unsigned char mask_info_buffer[FIELD_OFFSET(BITMAPINFO, bmiColors)
1588                            + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)];
1589     BITMAPINFO *mask_bits_info = (BITMAPINFO *)mask_info_buffer;
1590     struct emf *emf = dc_attr->emf;
1591     BITMAPINFO mask_info = {{ sizeof( mask_info.bmiHeader ) }};
1592     BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
1593     HBITMAP bitmap, blit_bitmap = NULL, mask_bitmap = NULL;
1594     UINT bmi_size, size, mask_info_size = 0;
1595     EMRPLGBLT *emr = NULL;
1596     BITMAPINFO *bmi;
1597     HDC blit_dc, mask_dc = NULL;
1598     int x_min, y_min, x_max, y_max, i;
1599     BOOL ret = FALSE;
1600 
1601     if (hdc_src && GDI_HANDLE_GET_TYPE(hdc_src) == GDILoObjType_LO_ALTDC_TYPE)
1602     {
1603         WINEDC * pldc = get_dc_ptr(hdc_src);
1604 
1605         if (pldc->iType == LDC_EMFLDC)
1606         {
1607             return FALSE;
1608         }
1609     }
1610 
1611     if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
1612 
1613     blit_dc = hdc_src;
1614     blit_bitmap = bitmap;
1615     if (!(bmi_size = get_bitmap_info( &blit_dc, &blit_bitmap, &src_info ))) return FALSE;
1616 
1617     if (mask)
1618     {
1619         mask_dc = hdc_src;
1620         mask_bitmap = mask;
1621         if (!(mask_info_size = get_bitmap_info( &mask_dc, &mask_bitmap, &mask_info ))) goto err;
1622         if (mask_info.bmiHeader.biBitCount == 1)
1623             mask_info_size = sizeof(BITMAPINFOHEADER); /* don't include colors */
1624     }
1625     else mask_info.bmiHeader.biSizeImage = 0;
1626 
1627     size = sizeof(*emr) + bmi_size + src_info.bmiHeader.biSizeImage +
1628         mask_info_size + mask_info.bmiHeader.biSizeImage;
1629 
1630     if (!(emr = HeapAlloc(GetProcessHeap(), 0, size))) goto err;
1631 
1632     emr->emr.iType = EMR_PLGBLT;
1633     emr->emr.nSize = size;
1634 
1635     /* FIXME: not exactly what native does */
1636     x_min = x_max = points[1].x + points[2].x - points[0].x;
1637     y_min = y_max = points[1].y + points[2].y - points[0].y;
1638     for (i = 0; i < ARRAYSIZE(emr->aptlDest); i++)
1639     {
1640         x_min = min( x_min, points[i].x );
1641         y_min = min( y_min, points[i].y );
1642         x_max = max( x_max, points[i].x );
1643         y_max = max( y_min, points[i].y );
1644     }
1645     emr->rclBounds.left = x_min;
1646     emr->rclBounds.top = y_min;
1647     emr->rclBounds.right = x_max;
1648     emr->rclBounds.bottom = y_max;
1649     memcpy( emr->aptlDest, points, sizeof(emr->aptlDest) );
1650     emr->xSrc = x_src;
1651     emr->ySrc = y_src;
1652     emr->cxSrc = width;
1653     emr->cySrc = height;
1654     NtGdiGetTransform( hdc_src, GdiWorldSpaceToDeviceSpace, &emr->xformSrc );
1655     emr->crBkColorSrc = GetBkColor( hdc_src );
1656     emr->iUsageSrc = DIB_RGB_COLORS;
1657     emr->offBmiSrc = sizeof(*emr);
1658     emr->cbBmiSrc = bmi_size;
1659     emr->offBitsSrc = emr->offBmiSrc + bmi_size;
1660     emr->cbBitsSrc = src_info.bmiHeader.biSizeImage;
1661     emr->xMask = x_mask;
1662     emr->yMask = y_mask;
1663     emr->iUsageMask = DIB_PAL_MONO;
1664     emr->offBmiMask = mask_info_size ? emr->offBitsSrc + emr->cbBitsSrc : 0;
1665     emr->cbBmiMask = mask_info_size;
1666     emr->offBitsMask = emr->offBmiMask + emr->cbBmiMask;
1667     emr->cbBitsMask = mask_info.bmiHeader.biSizeImage;
1668 
1669     bmi = (BITMAPINFO *)((char *)emr + emr->offBmiSrc);
1670     bmi->bmiHeader = src_info.bmiHeader;
1671     ret = GetDIBits( blit_dc, blit_bitmap, 0, src_info.bmiHeader.biHeight,
1672                      (char *)emr + emr->offBitsSrc, bmi, DIB_RGB_COLORS );
1673     if (!ret) goto err;
1674 
1675     if (mask_info_size)
1676     {
1677         mask_bits_info->bmiHeader = mask_info.bmiHeader;
1678         ret = GetDIBits( blit_dc, mask_bitmap, 0, mask_info.bmiHeader.biHeight,
1679                          (char *)emr + emr->offBitsMask, mask_bits_info, DIB_RGB_COLORS );
1680         if (ret) memcpy( (char *)emr + emr->offBmiMask, mask_bits_info, mask_info_size );
1681     }
1682 
1683     if (ret)
1684     {
1685         ret = emfdc_record( emf, (EMR *)emr );
1686         if (ret) emfdc_update_bounds( emf, &emr->rclBounds );
1687     }
1688 
1689 err:
1690     HeapFree( GetProcessHeap(), 0, emr );
1691     if (mask_bitmap != mask) DeleteObject( mask_bitmap );
1692     if (mask_dc != hdc_src) DeleteObject( mask_dc );
1693     if (blit_bitmap != bitmap) DeleteObject( blit_bitmap );
1694     if (blit_dc != hdc_src) DeleteDC( blit_dc );
1695     return ret;
1696 }
1697 
EMFDC_StretchDIBits(WINEDC * dc_attr,INT x_dst,INT y_dst,INT width_dst,INT height_dst,INT x_src,INT y_src,INT width_src,INT height_src,const void * bits,const BITMAPINFO * info,UINT usage,DWORD rop)1698 BOOL EMFDC_StretchDIBits( WINEDC *dc_attr, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
1699                           INT x_src, INT y_src, INT width_src, INT height_src, const void *bits,
1700                           const BITMAPINFO *info, UINT usage, DWORD rop )
1701 {
1702     EMRSTRETCHDIBITS *emr;
1703     BOOL ret;
1704     UINT bmi_size, emr_size;
1705 
1706     /* calculate the size of the colour table */
1707     bmi_size = get_dib_info_size( info, usage );
1708 
1709     emr_size = sizeof (EMRSTRETCHDIBITS) + bmi_size + info->bmiHeader.biSizeImage;
1710     if (!(emr = HeapAlloc(GetProcessHeap(), 0, emr_size ))) return 0;
1711 
1712     /* write a bitmap info header (with colours) to the record */
1713     memcpy( &emr[1], info, bmi_size);
1714 
1715     /* write bitmap bits to the record */
1716     memcpy ( (BYTE *)&emr[1] + bmi_size, bits, info->bmiHeader.biSizeImage );
1717 
1718     /* fill in the EMR header at the front of our piece of memory */
1719     emr->emr.iType = EMR_STRETCHDIBITS;
1720     emr->emr.nSize = emr_size;
1721 
1722     emr->xDest     = x_dst;
1723     emr->yDest     = y_dst;
1724     emr->cxDest    = width_dst;
1725     emr->cyDest    = height_dst;
1726     emr->dwRop     = rop;
1727     emr->xSrc      = x_src;
1728     emr->ySrc      = y_src;
1729 
1730     emr->iUsageSrc    = usage;
1731     emr->offBmiSrc    = sizeof (EMRSTRETCHDIBITS);
1732     emr->cbBmiSrc     = bmi_size;
1733     emr->offBitsSrc   = emr->offBmiSrc + bmi_size;
1734     emr->cbBitsSrc    = info->bmiHeader.biSizeImage;
1735 
1736     emr->cxSrc = width_src;
1737     emr->cySrc = height_src;
1738 
1739     emr->rclBounds.left   = x_dst;
1740     emr->rclBounds.top    = y_dst;
1741     emr->rclBounds.right  = x_dst + width_dst;
1742     emr->rclBounds.bottom = y_dst + height_dst;
1743 
1744     /* save the record we just created */
1745     ret = emfdc_record( dc_attr->emf, &emr->emr );
1746     if (ret) emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1747     HeapFree( GetProcessHeap(), 0, emr );
1748     return ret;
1749 }
1750 
EMFDC_SetDIBitsToDevice(WINEDC * dc_attr,INT x_dst,INT y_dst,DWORD width,DWORD height,INT x_src,INT y_src,UINT startscan,UINT lines,const void * bits,const BITMAPINFO * info,UINT usage)1751 BOOL EMFDC_SetDIBitsToDevice( WINEDC *dc_attr, INT x_dst, INT y_dst, DWORD width, DWORD height,
1752                               INT x_src, INT y_src, UINT startscan, UINT lines,
1753                               const void *bits, const BITMAPINFO *info, UINT usage )
1754 {
1755     EMRSETDIBITSTODEVICE *emr;
1756     DWORD bmiSize = get_dib_info_size( info, usage );
1757     DWORD size = sizeof(EMRSETDIBITSTODEVICE) + bmiSize + info->bmiHeader.biSizeImage;
1758     BOOL ret;
1759 
1760     if (!(emr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
1761 
1762     emr->emr.iType = EMR_SETDIBITSTODEVICE;
1763     emr->emr.nSize = size;
1764     emr->rclBounds.left = x_dst;
1765     emr->rclBounds.top = y_dst;
1766     emr->rclBounds.right = x_dst + width - 1;
1767     emr->rclBounds.bottom = y_dst + height - 1;
1768     emr->xDest = x_dst;
1769     emr->yDest = y_dst;
1770     emr->xSrc = x_src;
1771     emr->ySrc = y_src;
1772     emr->cxSrc = width;
1773     emr->cySrc = height;
1774     emr->offBmiSrc = sizeof(EMRSETDIBITSTODEVICE);
1775     emr->cbBmiSrc = bmiSize;
1776     emr->offBitsSrc = sizeof(EMRSETDIBITSTODEVICE) + bmiSize;
1777     emr->cbBitsSrc = info->bmiHeader.biSizeImage;
1778     emr->iUsageSrc = usage;
1779     emr->iStartScan = startscan;
1780     emr->cScans = lines;
1781     memcpy( (BYTE*)emr + emr->offBmiSrc, info, bmiSize );
1782     memcpy( (BYTE*)emr + emr->offBitsSrc, bits, info->bmiHeader.biSizeImage );
1783 
1784     if ((ret = emfdc_record( dc_attr->emf, (EMR*)emr )))
1785         emfdc_update_bounds( dc_attr->emf, &emr->rclBounds );
1786 
1787     HeapFree( GetProcessHeap(), 0, emr );
1788     return ret;
1789 }
1790 
EMFDC_SetDCBrushColor(WINEDC * dc_attr,COLORREF color)1791 BOOL EMFDC_SetDCBrushColor( WINEDC *dc_attr, COLORREF color )
1792 {
1793     struct emf *emf = dc_attr->emf;
1794     EMRSELECTOBJECT emr;
1795     DWORD index;
1796 
1797     if (GetCurrentObject( dc_attr->hdc, OBJ_BRUSH ) != GetStockObject( DC_BRUSH )) return TRUE;
1798 
1799     if (emf->dc_brush) DeleteObject( emf->dc_brush );
1800     if (!(emf->dc_brush = CreateSolidBrush( color ))) return FALSE;
1801     if (!(index = emfdc_create_brush( emf, emf->dc_brush ))) return FALSE;
1802     GDI_hdc_using_object( emf->dc_brush, dc_attr->hdc);//, emfdc_delete_object );
1803     emr.emr.iType = EMR_SELECTOBJECT;
1804     emr.emr.nSize = sizeof(emr);
1805     emr.ihObject = index;
1806     return emfdc_record( emf, &emr.emr );
1807 }
1808 
EMFDC_SetDCPenColor(WINEDC * dc_attr,COLORREF color)1809 BOOL EMFDC_SetDCPenColor( WINEDC *dc_attr, COLORREF color )
1810 {
1811     struct emf *emf = dc_attr->emf;
1812     EMRSELECTOBJECT emr;
1813     DWORD index;
1814     LOGPEN logpen = { PS_SOLID, { 0, 0 }, color };
1815 
1816     if (GetCurrentObject( dc_attr->hdc, OBJ_PEN ) != GetStockObject( DC_PEN )) return TRUE;
1817 
1818     if (emf->dc_pen) DeleteObject( emf->dc_pen );
1819     if (!(emf->dc_pen = CreatePenIndirect( &logpen ))) return FALSE;
1820     if (!(index = emfdc_create_pen( emf, emf->dc_pen ))) return FALSE;
1821     GDI_hdc_using_object( emf->dc_pen, dc_attr->hdc);//, emfdc_delete_object );
1822     emr.emr.iType = EMR_SELECTOBJECT;
1823     emr.emr.nSize = sizeof(emr);
1824     emr.ihObject = index;
1825     return emfdc_record( emf, &emr.emr );
1826 }
1827 
EMFDC_SaveDC(WINEDC * dc_attr)1828 BOOL EMFDC_SaveDC( WINEDC *dc_attr )
1829 {
1830     EMRSAVEDC emr;
1831 
1832     emr.emr.iType = EMR_SAVEDC;
1833     emr.emr.nSize = sizeof(emr);
1834     return emfdc_record( dc_attr->emf, &emr.emr );
1835 }
1836 #define GdiGetEMFRestorDc 5
EMFDC_RestoreDC(WINEDC * dc_attr,INT level)1837 BOOL EMFDC_RestoreDC( WINEDC *dc_attr, INT level )
1838 {
1839     EMRRESTOREDC emr;
1840 
1841     /* The Restore DC function needs the save level to be set correctly.
1842        Note that wine's level is 0 based, while our's is (like win) 1 based. */
1843     dc_attr->save_level = GetDCDWord(dc_attr->hdc, GdiGetEMFRestorDc, 0)  - 1;
1844 
1845     if (abs(level) > dc_attr->save_level || level == 0) return FALSE;
1846 
1847     emr.emr.iType = EMR_RESTOREDC;
1848     emr.emr.nSize = sizeof(emr);
1849     if (level < 0)
1850         emr.iRelative = level;
1851     else
1852         emr.iRelative = level - dc_attr->save_level - 1;
1853     return emfdc_record( dc_attr->emf, &emr.emr );
1854 }
1855 
EMFDC_SetTextAlign(WINEDC * dc_attr,UINT align)1856 BOOL EMFDC_SetTextAlign( WINEDC *dc_attr, UINT align )
1857 {
1858     EMRSETTEXTALIGN emr;
1859 
1860     emr.emr.iType = EMR_SETTEXTALIGN;
1861     emr.emr.nSize = sizeof(emr);
1862     emr.iMode = align;
1863     return emfdc_record( dc_attr->emf, &emr.emr );
1864 }
1865 
EMFDC_SetTextJustification(WINEDC * dc_attr,INT extra,INT breaks)1866 BOOL EMFDC_SetTextJustification( WINEDC *dc_attr, INT extra, INT breaks )
1867 {
1868     EMRSETTEXTJUSTIFICATION emr;
1869 
1870     emr.emr.iType = EMR_SETTEXTJUSTIFICATION;
1871     emr.emr.nSize = sizeof(emr);
1872     emr.nBreakExtra = extra;
1873     emr.nBreakCount = breaks;
1874     return emfdc_record( dc_attr->emf, &emr.emr );
1875 }
1876 
EMFDC_SetBkMode(WINEDC * dc_attr,INT mode)1877 BOOL EMFDC_SetBkMode( WINEDC *dc_attr, INT mode )
1878 {
1879     EMRSETBKMODE emr;
1880 
1881     emr.emr.iType = EMR_SETBKMODE;
1882     emr.emr.nSize = sizeof(emr);
1883     emr.iMode = mode;
1884     return emfdc_record( dc_attr->emf, &emr.emr );
1885 }
1886 
EMFDC_SetBkColor(WINEDC * dc_attr,COLORREF color)1887 BOOL EMFDC_SetBkColor( WINEDC *dc_attr, COLORREF color )
1888 {
1889     EMRSETBKCOLOR emr;
1890 
1891     emr.emr.iType = EMR_SETBKCOLOR;
1892     emr.emr.nSize = sizeof(emr);
1893     emr.crColor = color;
1894     return emfdc_record( dc_attr->emf, &emr.emr );
1895 }
1896 
EMFDC_SetTextColor(WINEDC * dc_attr,COLORREF color)1897 BOOL EMFDC_SetTextColor( WINEDC *dc_attr, COLORREF color )
1898 {
1899     EMRSETTEXTCOLOR emr;
1900 
1901     emr.emr.iType = EMR_SETTEXTCOLOR;
1902     emr.emr.nSize = sizeof(emr);
1903     emr.crColor = color;
1904     return emfdc_record( dc_attr->emf, &emr.emr );
1905 }
1906 
EMFDC_SetROP2(WINEDC * dc_attr,INT rop)1907 BOOL EMFDC_SetROP2( WINEDC *dc_attr, INT rop )
1908 {
1909     EMRSETROP2 emr;
1910 
1911     emr.emr.iType = EMR_SETROP2;
1912     emr.emr.nSize = sizeof(emr);
1913     emr.iMode = rop;
1914     return emfdc_record( dc_attr->emf, &emr.emr );
1915 }
1916 
EMFDC_SetPolyFillMode(WINEDC * dc_attr,INT mode)1917 BOOL EMFDC_SetPolyFillMode( WINEDC *dc_attr, INT mode )
1918 {
1919     EMRSETPOLYFILLMODE emr;
1920 
1921     emr.emr.iType = EMR_SETPOLYFILLMODE;
1922     emr.emr.nSize = sizeof(emr);
1923     emr.iMode = mode;
1924     return emfdc_record( dc_attr->emf, &emr.emr );
1925 }
1926 
EMFDC_SetStretchBltMode(WINEDC * dc_attr,INT mode)1927 BOOL EMFDC_SetStretchBltMode( WINEDC *dc_attr, INT mode )
1928 {
1929     EMRSETSTRETCHBLTMODE emr;
1930 
1931     emr.emr.iType = EMR_SETSTRETCHBLTMODE;
1932     emr.emr.nSize = sizeof(emr);
1933     emr.iMode = mode;
1934     return emfdc_record( dc_attr->emf, &emr.emr );
1935 }
1936 
EMFDC_SetArcDirection(WINEDC * dc_attr,INT dir)1937 BOOL EMFDC_SetArcDirection( WINEDC *dc_attr, INT dir )
1938 {
1939     EMRSETARCDIRECTION emr;
1940 
1941     emr.emr.iType = EMR_SETARCDIRECTION;
1942     emr.emr.nSize = sizeof(emr);
1943     emr.iArcDirection = dir;
1944     return emfdc_record( dc_attr->emf, &emr.emr );
1945 }
1946 
EMFDC_ExcludeClipRect(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom)1947 BOOL EMFDC_ExcludeClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom )
1948 {
1949     EMREXCLUDECLIPRECT emr;
1950 
1951     emr.emr.iType      = EMR_EXCLUDECLIPRECT;
1952     emr.emr.nSize      = sizeof(emr);
1953     emr.rclClip.left   = left;
1954     emr.rclClip.top    = top;
1955     emr.rclClip.right  = right;
1956     emr.rclClip.bottom = bottom;
1957     return emfdc_record( dc_attr->emf, &emr.emr );
1958 }
1959 
EMFDC_IntersectClipRect(WINEDC * dc_attr,INT left,INT top,INT right,INT bottom)1960 BOOL EMFDC_IntersectClipRect( WINEDC *dc_attr, INT left, INT top, INT right, INT bottom)
1961 {
1962     EMRINTERSECTCLIPRECT emr;
1963 
1964     emr.emr.iType      = EMR_INTERSECTCLIPRECT;
1965     emr.emr.nSize      = sizeof(emr);
1966     emr.rclClip.left   = left;
1967     emr.rclClip.top    = top;
1968     emr.rclClip.right  = right;
1969     emr.rclClip.bottom = bottom;
1970     return emfdc_record( dc_attr->emf, &emr.emr );
1971 }
1972 
EMFDC_OffsetClipRgn(WINEDC * dc_attr,INT x,INT y)1973 BOOL EMFDC_OffsetClipRgn( WINEDC *dc_attr, INT x, INT y )
1974 {
1975     EMROFFSETCLIPRGN emr;
1976 
1977     emr.emr.iType   = EMR_OFFSETCLIPRGN;
1978     emr.emr.nSize   = sizeof(emr);
1979     emr.ptlOffset.x = x;
1980     emr.ptlOffset.y = y;
1981     return emfdc_record( dc_attr->emf, &emr.emr );
1982 }
1983 
EMFDC_ExtSelectClipRgn(WINEDC * dc_attr,HRGN hrgn,INT mode)1984 BOOL EMFDC_ExtSelectClipRgn( WINEDC *dc_attr, HRGN hrgn, INT mode )
1985 {
1986     EMREXTSELECTCLIPRGN *emr;
1987     DWORD size, rgnsize;
1988     BOOL ret;
1989 
1990     if (!hrgn)
1991     {
1992         if (mode != RGN_COPY) return ERROR;
1993         rgnsize = 0;
1994     }
1995     else rgnsize = /*NtGdi*/GetRegionData( hrgn, 0, NULL );
1996 
1997     size = rgnsize + offsetof(EMREXTSELECTCLIPRGN,RgnData);
1998     emr = HeapAlloc( GetProcessHeap(), 0, size );
1999     if (rgnsize) /*NtGdi*/GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
2000 
2001     emr->emr.iType = EMR_EXTSELECTCLIPRGN;
2002     emr->emr.nSize = size;
2003     emr->cbRgnData = rgnsize;
2004     emr->iMode     = mode;
2005 
2006     ret = emfdc_record( dc_attr->emf, &emr->emr );
2007     HeapFree( GetProcessHeap(), 0, emr );
2008     return ret;
2009 }
2010 
EMFDC_SetMapMode(WINEDC * dc_attr,INT mode)2011 BOOL EMFDC_SetMapMode( WINEDC *dc_attr, INT mode )
2012 {
2013     EMRSETMAPMODE emr;
2014 
2015     emr.emr.iType = EMR_SETMAPMODE;
2016     emr.emr.nSize = sizeof(emr);
2017     emr.iMode = mode;
2018     return emfdc_record( dc_attr->emf, &emr.emr );
2019 }
2020 
EMFDC_SetViewportExtEx(WINEDC * dc_attr,INT cx,INT cy)2021 BOOL EMFDC_SetViewportExtEx( WINEDC *dc_attr, INT cx, INT cy )
2022 {
2023     EMRSETVIEWPORTEXTEX emr;
2024 
2025     emr.emr.iType = EMR_SETVIEWPORTEXTEX;
2026     emr.emr.nSize = sizeof(emr);
2027     emr.szlExtent.cx = cx;
2028     emr.szlExtent.cy = cy;
2029     return emfdc_record( dc_attr->emf, &emr.emr );
2030 }
2031 
EMFDC_SetWindowExtEx(WINEDC * dc_attr,INT cx,INT cy)2032 BOOL EMFDC_SetWindowExtEx( WINEDC *dc_attr, INT cx, INT cy )
2033 {
2034     EMRSETWINDOWEXTEX emr;
2035 
2036     emr.emr.iType = EMR_SETWINDOWEXTEX;
2037     emr.emr.nSize = sizeof(emr);
2038     emr.szlExtent.cx = cx;
2039     emr.szlExtent.cy = cy;
2040     return emfdc_record( dc_attr->emf, &emr.emr );
2041 }
2042 
EMFDC_SetViewportOrgEx(WINEDC * dc_attr,INT x,INT y)2043 BOOL EMFDC_SetViewportOrgEx( WINEDC *dc_attr, INT x, INT y )
2044 {
2045     EMRSETVIEWPORTORGEX emr;
2046 
2047     emr.emr.iType = EMR_SETVIEWPORTORGEX;
2048     emr.emr.nSize = sizeof(emr);
2049     emr.ptlOrigin.x = x;
2050     emr.ptlOrigin.y = y;
2051     return emfdc_record( dc_attr->emf, &emr.emr );
2052 }
2053 
EMFDC_SetWindowOrgEx(WINEDC * dc_attr,INT x,INT y)2054 BOOL EMFDC_SetWindowOrgEx( WINEDC *dc_attr, INT x, INT y )
2055 {
2056     EMRSETWINDOWORGEX emr;
2057 
2058     emr.emr.iType = EMR_SETWINDOWORGEX;
2059     emr.emr.nSize = sizeof(emr);
2060     emr.ptlOrigin.x = x;
2061     emr.ptlOrigin.y = y;
2062     return emfdc_record( dc_attr->emf, &emr.emr );
2063 }
2064 
EMFDC_ScaleViewportExtEx(WINEDC * dc_attr,INT x_num,INT x_denom,INT y_num,INT y_denom)2065 BOOL EMFDC_ScaleViewportExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
2066 {
2067     EMRSCALEVIEWPORTEXTEX emr;
2068 
2069     emr.emr.iType = EMR_SCALEVIEWPORTEXTEX;
2070     emr.emr.nSize = sizeof(emr);
2071     emr.xNum      = x_num;
2072     emr.xDenom    = x_denom;
2073     emr.yNum      = y_num;
2074     emr.yDenom    = y_denom;
2075     return emfdc_record( dc_attr->emf, &emr.emr );
2076 }
2077 
EMFDC_ScaleWindowExtEx(WINEDC * dc_attr,INT x_num,INT x_denom,INT y_num,INT y_denom)2078 BOOL EMFDC_ScaleWindowExtEx( WINEDC *dc_attr, INT x_num, INT x_denom, INT y_num, INT y_denom )
2079 {
2080     EMRSCALEWINDOWEXTEX emr;
2081 
2082     emr.emr.iType = EMR_SCALEWINDOWEXTEX;
2083     emr.emr.nSize = sizeof(emr);
2084     emr.xNum      = x_num;
2085     emr.xDenom    = x_denom;
2086     emr.yNum      = y_num;
2087     emr.yDenom    = y_denom;
2088     return emfdc_record( dc_attr->emf, &emr.emr );
2089 }
2090 
EMFDC_SetLayout(WINEDC * dc_attr,DWORD layout)2091 BOOL EMFDC_SetLayout( WINEDC *dc_attr, DWORD layout )
2092 {
2093     EMRSETLAYOUT emr;
2094 
2095     emr.emr.iType = EMR_SETLAYOUT;
2096     emr.emr.nSize = sizeof(emr);
2097     emr.iMode = layout;
2098     return emfdc_record( dc_attr->emf, &emr.emr );
2099 }
2100 
EMFDC_SetWorldTransform(WINEDC * dc_attr,const XFORM * xform)2101 BOOL EMFDC_SetWorldTransform( WINEDC *dc_attr, const XFORM *xform )
2102 {
2103     EMRSETWORLDTRANSFORM emr;
2104 
2105     emr.emr.iType = EMR_SETWORLDTRANSFORM;
2106     emr.emr.nSize = sizeof(emr);
2107     emr.xform = *xform;
2108     return emfdc_record( dc_attr->emf, &emr.emr );
2109 }
2110 
EMFDC_ModifyWorldTransform(WINEDC * dc_attr,const XFORM * xform,DWORD mode)2111 BOOL EMFDC_ModifyWorldTransform( WINEDC *dc_attr, const XFORM *xform, DWORD mode )
2112 {
2113     EMRMODIFYWORLDTRANSFORM emr;
2114 
2115     emr.emr.iType = EMR_MODIFYWORLDTRANSFORM;
2116     emr.emr.nSize = sizeof(emr);
2117     if (mode == MWT_IDENTITY)
2118     {
2119         emr.xform.eM11 = 1.0f;
2120         emr.xform.eM12 = 0.0f;
2121         emr.xform.eM21 = 0.0f;
2122         emr.xform.eM22 = 1.0f;
2123         emr.xform.eDx = 0.0f;
2124         emr.xform.eDy = 0.0f;
2125     }
2126     else
2127     {
2128         emr.xform = *xform;
2129     }
2130     emr.iMode = mode;
2131     return emfdc_record( dc_attr->emf, &emr.emr );
2132 }
2133 
EMFDC_SetMapperFlags(WINEDC * dc_attr,DWORD flags)2134 BOOL EMFDC_SetMapperFlags( WINEDC *dc_attr, DWORD flags )
2135 {
2136     EMRSETMAPPERFLAGS emr;
2137 
2138     emr.emr.iType = EMR_SETMAPPERFLAGS;
2139     emr.emr.nSize = sizeof(emr);
2140     emr.dwFlags   = flags;
2141     return emfdc_record( dc_attr->emf, &emr.emr );
2142 }
2143 
EMFDC_AbortPath(WINEDC * dc_attr)2144 BOOL EMFDC_AbortPath( WINEDC *dc_attr )
2145 {
2146     struct emf *emf = dc_attr->emf;
2147     EMRABORTPATH emr;
2148 
2149     emr.emr.iType = EMR_ABORTPATH;
2150     emr.emr.nSize = sizeof(emr);
2151 
2152     emf->path = FALSE;
2153     return emfdc_record( dc_attr->emf, &emr.emr );
2154 }
2155 
EMFDC_BeginPath(WINEDC * dc_attr)2156 BOOL EMFDC_BeginPath( WINEDC *dc_attr )
2157 {
2158     struct emf *emf = dc_attr->emf;
2159     EMRBEGINPATH emr;
2160 
2161     emr.emr.iType = EMR_BEGINPATH;
2162     emr.emr.nSize = sizeof(emr);
2163     if (!emfdc_record( emf, &emr.emr )) return FALSE;
2164 
2165     emf->path = TRUE;
2166     return TRUE;
2167 }
2168 
EMFDC_CloseFigure(WINEDC * dc_attr)2169 BOOL EMFDC_CloseFigure( WINEDC *dc_attr )
2170 {
2171     EMRCLOSEFIGURE emr;
2172 
2173     emr.emr.iType = EMR_CLOSEFIGURE;
2174     emr.emr.nSize = sizeof(emr);
2175     return emfdc_record( dc_attr->emf, &emr.emr );
2176 }
2177 
EMFDC_EndPath(WINEDC * dc_attr)2178 BOOL EMFDC_EndPath( WINEDC *dc_attr )
2179 {
2180     struct emf *emf = dc_attr->emf;
2181     EMRENDPATH emr;
2182 
2183     emf->path = FALSE;
2184 
2185     emr.emr.iType = EMR_ENDPATH;
2186     emr.emr.nSize = sizeof(emr);
2187     return emfdc_record( emf, &emr.emr );
2188 }
2189 
EMFDC_FlattenPath(WINEDC * dc_attr)2190 BOOL EMFDC_FlattenPath( WINEDC *dc_attr )
2191 {
2192     EMRFLATTENPATH emr;
2193 
2194     emr.emr.iType = EMR_FLATTENPATH;
2195     emr.emr.nSize = sizeof(emr);
2196     return emfdc_record( dc_attr->emf, &emr.emr );
2197 }
2198 
EMFDC_SelectClipPath(WINEDC * dc_attr,INT mode)2199 BOOL EMFDC_SelectClipPath( WINEDC *dc_attr, INT mode )
2200 {
2201     EMRSELECTCLIPPATH emr;
2202 
2203     emr.emr.iType = EMR_SELECTCLIPPATH;
2204     emr.emr.nSize = sizeof(emr);
2205     emr.iMode = mode;
2206     return emfdc_record( dc_attr->emf, &emr.emr );
2207 }
2208 
EMFDC_WidenPath(WINEDC * dc_attr)2209 BOOL EMFDC_WidenPath( WINEDC *dc_attr )
2210 {
2211     EMRWIDENPATH emr;
2212 
2213     emr.emr.iType = EMR_WIDENPATH;
2214     emr.emr.nSize = sizeof(emr);
2215     return emfdc_record( dc_attr->emf, &emr.emr );
2216 }
2217 
EMFDC_DeleteDC(WINEDC * dc_attr)2218 BOOL EMFDC_DeleteDC( WINEDC *dc_attr )
2219 {
2220     struct emf *emf = dc_attr->emf;
2221     UINT index;
2222 
2223     HeapFree( GetProcessHeap(), 0, emf->emh );
2224     for (index = 0; index < emf->handles_size; index++)
2225         if (emf->handles[index])
2226             GDI_hdc_not_using_object( emf->handles[index], emf->dc_attr->hdc );
2227     HeapFree( GetProcessHeap(), 0, emf->handles );
2228     return TRUE;
2229 }
2230 
2231 //
2232 // Waiting on wine support....
2233 //
2234 
2235 
2236 //
2237 // ReactOS Print Support
2238 //
EMFDC_WriteEscape(WINEDC * dc_attr,INT nEscape,INT cbInput,LPSTR lpszInData,DWORD emrType)2239 BOOL EMFDC_WriteEscape( WINEDC *dc_attr, INT nEscape, INT cbInput, LPSTR lpszInData, DWORD emrType)
2240 {
2241     PEMRESCAPE pemr;
2242     UINT total, rounded_size;
2243     BOOL ret;
2244 
2245     rounded_size = (cbInput+3) & ~3;
2246     total = offsetof(EMRESCAPE,Data) + rounded_size;
2247 
2248     pemr = RtlAllocateHeap( GetProcessHeap(), 0, total );
2249     if ( !pemr )
2250         return 0;
2251 
2252     RtlZeroMemory( pemr, total );
2253 
2254     pemr->emr.iType = emrType;
2255     pemr->emr.nSize = total;
2256     pemr->iEsc      = nEscape;
2257     pemr->cjIn      = cbInput;
2258 
2259     RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput );
2260 
2261     ret = emfdc_record( dc_attr->emf, &pemr->emr );
2262 
2263     RtlFreeHeap( GetProcessHeap(), 0, pemr );
2264     return ret;
2265 }
2266 
EMFDC_WriteNamedEscape(WINEDC * dc_attr,PWCHAR pDriver,INT nEscape,INT cbInput,LPCSTR lpszInData)2267 BOOL EMFDC_WriteNamedEscape( WINEDC *dc_attr, PWCHAR pDriver, INT nEscape, INT cbInput, LPCSTR lpszInData)
2268 {
2269     PEMRNAMEDESCAPE pemr;
2270     UINT sizestr, total, rounded_size;
2271     INT ret;
2272 
2273     rounded_size = (cbInput+3) & ~3;
2274     total = offsetof(EMRNAMEDESCAPE,Data) + rounded_size;
2275 
2276     total += sizestr = (UINT)((wcslen(pDriver) + 1 ) * sizeof(WCHAR));
2277 
2278     pemr = RtlAllocateHeap( GetProcessHeap(), 0, total );
2279     if ( !pemr )
2280         return 0;
2281 
2282     RtlZeroMemory( pemr, total );
2283 
2284     pemr->emr.iType = EMR_NAMEDESCAPE;
2285     pemr->emr.nSize = total;
2286     pemr->iEsc      = nEscape;
2287     pemr->cjIn      = cbInput;
2288 
2289     RtlCopyMemory( &pemr->Data[0], lpszInData, cbInput );
2290     //
2291     // WARNING :
2292     //   Need to remember with wine, theses headers are relocatable.
2293     RtlCopyMemory( &pemr->Data[rounded_size], pDriver, sizestr );
2294 
2295     ret = emfdc_record( dc_attr->emf, &pemr->emr );
2296 
2297     RtlFreeHeap( GetProcessHeap(), 0, pemr );
2298     return ret;
2299 }
2300 
EMFDC_SetMetaRgn(WINEDC * dc_attr)2301 BOOL EMFDC_SetMetaRgn( WINEDC *dc_attr )
2302 {
2303     EMRSETMETARGN emr;
2304 
2305     emr.emr.iType = EMR_SETMETARGN;
2306     emr.emr.nSize = sizeof(emr);
2307 
2308     return emfdc_record( dc_attr->emf, &emr.emr );
2309 }
2310 
EMFDC_SetBrushOrg(WINEDC * dc_attr,INT x,INT y)2311 BOOL EMFDC_SetBrushOrg( WINEDC *dc_attr, INT x, INT y)
2312 {
2313     EMRSETBRUSHORGEX emr;
2314 
2315     emr.emr.iType = EMR_SETBRUSHORGEX;
2316     emr.emr.nSize = sizeof(emr);
2317     emr.ptlOrigin.x = x;
2318     emr.ptlOrigin.y = y;
2319 
2320     return emfdc_record( dc_attr->emf, &emr.emr );
2321 }
2322 
2323 /*******************************************************************
2324  *      GdiComment   (GDI32.@)
2325  */
EMFDC_GdiComment(HDC hdc,UINT bytes,const BYTE * buffer)2326 BOOL WINAPI EMFDC_GdiComment( HDC hdc, UINT bytes, const BYTE *buffer )
2327 {
2328     WINEDC *dc_attr;
2329     EMRGDICOMMENT *emr;
2330     UINT total, rounded_size;
2331     BOOL ret;
2332 
2333     if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return FALSE;
2334 
2335     rounded_size = (bytes+3) & ~3;
2336     total = offsetof(EMRGDICOMMENT,Data) + rounded_size;
2337 
2338     emr = HeapAlloc(GetProcessHeap(), 0, total);
2339     emr->emr.iType = EMR_GDICOMMENT;
2340     emr->emr.nSize = total;
2341     emr->cbData = bytes;
2342     memset(&emr->Data[bytes], 0, rounded_size - bytes);
2343     memcpy(&emr->Data[0], buffer, bytes);
2344 
2345     ret = emfdc_record( dc_attr->emf, &emr->emr );
2346 
2347     HeapFree(GetProcessHeap(), 0, emr);
2348 
2349     return ret;
2350 }
2351 
2352 /**********************************************************************
2353  *           CreateEnhMetaFileA   (GDI32.@)
2354  */
CreateEnhMetaFileA(HDC hdc,const char * filename,const RECT * rect,const char * description)2355 HDC WINAPI CreateEnhMetaFileA( HDC hdc, const char *filename, const RECT *rect,
2356                                const char *description )
2357 {
2358     WCHAR *filenameW = NULL;
2359     WCHAR *descriptionW = NULL;
2360     DWORD len1, len2, total;
2361     HDC ret;
2362 
2363     if (filename)
2364     {
2365         total = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
2366         filenameW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
2367         MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, total );
2368     }
2369 
2370     if(description)
2371     {
2372         len1 = (DWORD)strlen(description);
2373         len2 = (DWORD)strlen(description + len1 + 1);
2374         total = MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, NULL, 0 );
2375         descriptionW = HeapAlloc( GetProcessHeap(), 0, total * sizeof(WCHAR) );
2376         MultiByteToWideChar( CP_ACP, 0, description, len1 + len2 + 3, descriptionW, total );
2377     }
2378 
2379     ret = CreateEnhMetaFileW( hdc, filenameW, rect, descriptionW );
2380 
2381     HeapFree( GetProcessHeap(), 0, filenameW );
2382     HeapFree( GetProcessHeap(), 0, descriptionW );
2383     return ret;
2384 }
2385 
2386 /**********************************************************************
2387  *           CreateEnhMetaFileW   (GDI32.@)
2388  */
CreateEnhMetaFileW(HDC hdc,const WCHAR * filename,const RECT * rect,const WCHAR * description)2389 HDC WINAPI CreateEnhMetaFileW( HDC hdc, const WCHAR *filename, const RECT *rect,
2390                                const WCHAR *description )
2391 {
2392     HDC ret;
2393     struct emf *emf;
2394     WINEDC *dc_attr;
2395     HANDLE file;
2396     DWORD size = 0, length = 0;
2397 
2398     TRACE( "(%p %s %s %s)\n", hdc, debugstr_w(filename), wine_dbgstr_rect(rect),
2399            debugstr_w(description) );
2400 
2401     //if (!(ret = NtGdiCreateMetafileDC( hdc ))) return 0;
2402     if(!(dc_attr = alloc_dc_ptr(OBJ_ENHMETADC)))
2403     {
2404        if (dc_attr->hdc) DeleteDC( dc_attr->hdc );
2405        return 0;
2406     }
2407 
2408     ret = dc_attr->hdc;
2409 
2410     if (/*!(dc_attr = get_dc_ptr( ret )) ||*/ !(emf = HeapAlloc( GetProcessHeap(), 0, sizeof(*emf) )))
2411     {
2412         DeleteDC( ret );
2413         return 0;
2414     }
2415 
2416     emf->dc_attr = dc_attr;
2417     dc_attr->emf = emf;
2418 
2419     if (description) /* App name\0Title\0\0 */
2420     {
2421         length = lstrlenW( description );
2422         length += lstrlenW( description + length + 1 );
2423         length += 3;
2424         length *= 2;
2425     }
2426     size = sizeof(ENHMETAHEADER) + (length + 3) / 4 * 4;
2427 
2428     if (!(emf->emh = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size)))
2429     {
2430         DeleteDC( ret );
2431         return 0;
2432     }
2433     emf->dc_attr = dc_attr;
2434 
2435     emf->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
2436                               HANDLE_LIST_INC * sizeof(emf->handles[0]) );
2437     emf->handles_size = HANDLE_LIST_INC;
2438     emf->cur_handles = 1;
2439     emf->file = 0;
2440     emf->dc_brush = 0;
2441     emf->dc_pen = 0;
2442     emf->path = FALSE;
2443 
2444     emf->emh->iType = EMR_HEADER;
2445     emf->emh->nSize = size;
2446 
2447     dc_attr->emf_bounds.left = dc_attr->emf_bounds.top = 0;
2448     dc_attr->emf_bounds.right = dc_attr->emf_bounds.bottom = -1;
2449 
2450     if (rect)
2451     {
2452         emf->emh->rclFrame.left   = rect->left;
2453         emf->emh->rclFrame.top    = rect->top;
2454         emf->emh->rclFrame.right  = rect->right;
2455         emf->emh->rclFrame.bottom = rect->bottom;
2456     }
2457     else
2458     {
2459         /* Set this to {0,0 - -1,-1} and update it at the end */
2460         emf->emh->rclFrame.left = emf->emh->rclFrame.top = 0;
2461         emf->emh->rclFrame.right = emf->emh->rclFrame.bottom = -1;
2462     }
2463 
2464     emf->emh->dSignature = ENHMETA_SIGNATURE;
2465     emf->emh->nVersion = 0x10000;
2466     emf->emh->nBytes = emf->emh->nSize;
2467     emf->emh->nRecords = 1;
2468     emf->emh->nHandles = 1;
2469 
2470     emf->emh->sReserved = 0; /* According to docs, this is reserved and must be 0 */
2471     emf->emh->nDescription = length / 2;
2472 
2473     emf->emh->offDescription = length ? sizeof(ENHMETAHEADER) : 0;
2474 
2475     emf->emh->nPalEntries = 0; /* I guess this should start at 0 */
2476 
2477     /* Size in pixels */
2478     emf->emh->szlDevice.cx = GetDeviceCaps( ret, HORZRES );
2479     emf->emh->szlDevice.cy = GetDeviceCaps( ret, VERTRES );
2480 
2481     /* Size in millimeters */
2482     emf->emh->szlMillimeters.cx = GetDeviceCaps( ret, HORZSIZE );
2483     emf->emh->szlMillimeters.cy = GetDeviceCaps( ret, VERTSIZE );
2484 
2485     /* Size in micrometers */
2486     emf->emh->szlMicrometers.cx = emf->emh->szlMillimeters.cx * 1000;
2487     emf->emh->szlMicrometers.cy = emf->emh->szlMillimeters.cy * 1000;
2488 
2489     memcpy( (char *)emf->emh + sizeof(ENHMETAHEADER), description, length );
2490 
2491     if (filename)  /* disk based metafile */
2492     {
2493         if ((file = CreateFileW( filename, GENERIC_WRITE | GENERIC_READ, 0,
2494                                   NULL, CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE)
2495         {
2496             DeleteDC( ret );
2497             return 0;
2498         }
2499         emf->file = file;
2500     }
2501 
2502     TRACE( "returning %p\n", ret );
2503     return ret;
2504 }
2505 
2506 /******************************************************************
2507  *           CloseEnhMetaFile (GDI32.@)
2508  */
CloseEnhMetaFile(HDC hdc)2509 HENHMETAFILE WINAPI CloseEnhMetaFile( HDC hdc )
2510 {
2511     HENHMETAFILE hmf;
2512     struct emf *emf;
2513     WINEDC *dc_attr;
2514     EMREOF emr;
2515     HANDLE mapping = 0;
2516 
2517     if (!(dc_attr = get_dc_ptr( hdc )) || !dc_attr->emf) return 0;
2518     emf = dc_attr->emf;
2519 
2520     if (dc_attr->save_level)
2521         RestoreDC( hdc, 1 );
2522 
2523     if (emf->dc_brush) DeleteObject( emf->dc_brush );
2524     if (emf->dc_pen) DeleteObject( emf->dc_pen );
2525 
2526     emr.emr.iType = EMR_EOF;
2527     emr.emr.nSize = sizeof(emr);
2528     emr.nPalEntries = 0;
2529     emr.offPalEntries = FIELD_OFFSET(EMREOF, nSizeLast);
2530     emr.nSizeLast = emr.emr.nSize;
2531     emfdc_record( emf, &emr.emr );
2532 
2533     emf->emh->rclBounds = dc_attr->emf_bounds;
2534 
2535     /* Update rclFrame if not initialized in CreateEnhMetaFile */
2536     if (emf->emh->rclFrame.left > emf->emh->rclFrame.right)
2537     {
2538         emf->emh->rclFrame.left = emf->emh->rclBounds.left *
2539             emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
2540         emf->emh->rclFrame.top = emf->emh->rclBounds.top *
2541             emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
2542         emf->emh->rclFrame.right = emf->emh->rclBounds.right *
2543             emf->emh->szlMillimeters.cx * 100 / emf->emh->szlDevice.cx;
2544         emf->emh->rclFrame.bottom = emf->emh->rclBounds.bottom *
2545             emf->emh->szlMillimeters.cy * 100 / emf->emh->szlDevice.cy;
2546     }
2547 
2548     if (emf->file)  /* disk based metafile */
2549     {
2550         DWORD bytes_written;
2551 
2552         if (!WriteFile( emf->file, emf->emh, emf->emh->nBytes, &bytes_written, NULL ))
2553         {
2554             CloseHandle( emf->file );
2555             return 0;
2556         }
2557         HeapFree( GetProcessHeap(), 0, emf->emh );
2558         mapping = CreateFileMappingA( emf->file, NULL, PAGE_READONLY, 0, 0, NULL );
2559         TRACE( "mapping = %p\n", mapping );
2560         emf->emh = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
2561         TRACE( "view = %p\n", emf->emh );
2562         CloseHandle( mapping );
2563         CloseHandle( emf->file );
2564     }
2565 
2566     hmf = EMF_Create_HENHMETAFILE( emf->emh, emf->emh->nBytes, emf->file != 0 );
2567     emf->emh = NULL;  /* So it won't be deleted */
2568     DeleteDC( hdc );
2569     return hmf;
2570 }
2571