2 * Enhanced MetaFile recording functions
4 * Copyright 1999 Huw D M Davies
5 * Copyright 2016 Alexandre Julliard
6 * Copyright 2021 Jacek Caban for CodeWeavers
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.
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.
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
26 #include "gdi_private.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile
);
38 UINT handles_size
, cur_handles
;
46 #define HANDLE_LIST_INC 20
47 static const RECTL empty_bounds
= { 0, 0, -1, -1 };
49 static BOOL
emfdc_record( struct emf
*emf
, EMR
*emr
)
54 TRACE( "record %d, size %d\n", emr
->iType
, emr
->nSize
);
56 assert( !(emr
->nSize
& 3) );
58 emf
->emh
->nBytes
+= emr
->nSize
;
61 size
= HeapSize( GetProcessHeap(), 0, emf
->emh
);
62 len
= emf
->emh
->nBytes
;
65 size
+= (size
/ 2) + emr
->nSize
;
66 emh
= HeapReAlloc( GetProcessHeap(), 0, emf
->emh
, size
);
67 if (!emh
) return FALSE
;
70 memcpy( (char *)emf
->emh
+ emf
->emh
->nBytes
- emr
->nSize
, emr
, emr
->nSize
);
74 static void emfdc_update_bounds( struct emf
*emf
, RECTL
*rect
)
76 RECTL
*bounds
= &emf
->dc_attr
->emf_bounds
;
77 RECTL vport_rect
= *rect
;
79 LPtoDP( emf
->dc_attr
->hdc
, (POINT
*)&vport_rect
, 2 );
81 /* The coordinate systems may be mirrored
82 (LPtoDP handles points, not rectangles) */
83 if (vport_rect
.left
> vport_rect
.right
)
85 LONG temp
= vport_rect
.right
;
86 vport_rect
.right
= vport_rect
.left
;
87 vport_rect
.left
= temp
;
89 if (vport_rect
.top
> vport_rect
.bottom
)
91 LONG temp
= vport_rect
.bottom
;
92 vport_rect
.bottom
= vport_rect
.top
;
93 vport_rect
.top
= temp
;
96 if (bounds
->left
> bounds
->right
)
98 /* first bounding rectangle */
103 bounds
->left
= min(bounds
->left
, vport_rect
.left
);
104 bounds
->top
= min(bounds
->top
, vport_rect
.top
);
105 bounds
->right
= max(bounds
->right
, vport_rect
.right
);
106 bounds
->bottom
= max(bounds
->bottom
, vport_rect
.bottom
);
110 static UINT
get_bitmap_info( HDC
*hdc
, HBITMAP
*bitmap
, BITMAPINFO
*info
)
117 if (!(info_size
= GetObjectW( *bitmap
, sizeof(dib
), &dib
))) return 0;
119 if (info_size
== sizeof(dib
))
122 blit_bitmap
= *bitmap
;
126 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
127 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
128 BITMAP bmp
= dib
.dsBm
;
132 assert( info_size
== sizeof(BITMAP
) );
134 dib_info
->bmiHeader
.biSize
= sizeof(dib_info
->bmiHeader
);
135 dib_info
->bmiHeader
.biWidth
= bmp
.bmWidth
;
136 dib_info
->bmiHeader
.biHeight
= bmp
.bmHeight
;
137 dib_info
->bmiHeader
.biPlanes
= 1;
138 dib_info
->bmiHeader
.biBitCount
= bmp
.bmBitsPixel
;
139 dib_info
->bmiHeader
.biCompression
= BI_RGB
;
140 dib_info
->bmiHeader
.biSizeImage
= 0;
141 dib_info
->bmiHeader
.biXPelsPerMeter
= 0;
142 dib_info
->bmiHeader
.biYPelsPerMeter
= 0;
143 dib_info
->bmiHeader
.biClrUsed
= 0;
144 dib_info
->bmiHeader
.biClrImportant
= 0;
145 switch (dib_info
->bmiHeader
.biBitCount
)
148 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
149 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
150 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
153 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
154 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
155 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
158 if (dib_info
->bmiHeader
.biBitCount
> 8) break;
159 if (!(palette
= GetCurrentObject( *hdc
, OBJ_PAL
))) return FALSE
;
160 if (!GetPaletteEntries( palette
, 0, 256, (PALETTEENTRY
*)dib_info
->bmiColors
))
164 if (!(blit_dc
= NtGdiCreateCompatibleDC( *hdc
))) return FALSE
;
165 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
167 if (!SelectObject( blit_dc
, blit_bitmap
)) goto err
;
168 if (!BitBlt( blit_dc
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, *hdc
, 0, 0, SRCCOPY
))
171 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, info
, DIB_RGB_COLORS
))
174 bpp
= info
->bmiHeader
.biBitCount
;
176 return sizeof(BITMAPINFOHEADER
) + (1 << bpp
) * sizeof(RGBQUAD
);
177 else if (bpp
== 16 || bpp
== 32)
178 return sizeof(BITMAPINFOHEADER
) + 3 * sizeof(RGBQUAD
);
180 return sizeof(BITMAPINFOHEADER
);
183 if (blit_dc
&& blit_dc
!= *hdc
) DeleteDC( blit_dc
);
184 if (blit_bitmap
&& blit_bitmap
!= *bitmap
) DeleteObject( blit_bitmap
);
188 /*******************************************************************************************
189 * Verify that the DIB parameters are valid.
191 static BOOL
is_valid_dib_format( const BITMAPINFOHEADER
*info
, BOOL allow_compression
)
193 if (info
->biWidth
<= 0) return FALSE
;
194 if (info
->biHeight
== 0) return FALSE
;
196 if (allow_compression
&& (info
->biCompression
== BI_RLE4
|| info
->biCompression
== BI_RLE8
))
198 if (info
->biHeight
< 0) return FALSE
;
199 if (!info
->biSizeImage
) return FALSE
;
200 return info
->biBitCount
== (info
->biCompression
== BI_RLE4
? 4 : 8);
203 if (!info
->biPlanes
) return FALSE
;
205 /* check for size overflow */
206 if (!info
->biBitCount
) return FALSE
;
207 if (UINT_MAX
/ info
->biBitCount
< info
->biWidth
) return FALSE
;
208 if (UINT_MAX
/ get_dib_stride( info
->biWidth
, info
->biBitCount
) < abs( info
->biHeight
)) return FALSE
;
210 switch (info
->biBitCount
)
216 return (info
->biCompression
== BI_RGB
);
219 return (info
->biCompression
== BI_BITFIELDS
|| info
->biCompression
== BI_RGB
);
225 static BOOL
emf_parse_user_bitmapinfo( BITMAPINFOHEADER
*dst
, const BITMAPINFOHEADER
*info
,
226 UINT coloruse
, BOOL allow_compression
,
227 UINT
*bmi_size
, UINT
*img_size
)
229 UINT colour_table_size
;
231 if (coloruse
> DIB_PAL_COLORS
+ 1) return FALSE
; /* FIXME: handle DIB_PAL_COLORS+1 format */
232 if (!info
) return FALSE
;
234 memset(dst
, 0, sizeof(*dst
));
236 if (info
->biSize
== sizeof(BITMAPCOREHEADER
))
238 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
239 dst
->biWidth
= core
->bcWidth
;
240 dst
->biHeight
= core
->bcHeight
;
241 dst
->biPlanes
= core
->bcPlanes
;
242 dst
->biBitCount
= core
->bcBitCount
;
243 dst
->biCompression
= BI_RGB
;
244 dst
->biXPelsPerMeter
= 0;
245 dst
->biYPelsPerMeter
= 0;
247 dst
->biClrImportant
= 0;
249 else if (info
->biSize
>= sizeof(BITMAPINFOHEADER
)) /* assume BITMAPINFOHEADER */
255 WARN( "(%u): unknown/wrong size for header\n", info
->biSize
);
259 dst
->biSize
= sizeof(*dst
);
261 if (!is_valid_dib_format( dst
, allow_compression
)) return FALSE
;
263 colour_table_size
= 0;
264 if (dst
->biCompression
== BI_BITFIELDS
)
266 colour_table_size
= 3 * sizeof(DWORD
);
268 else if (dst
->biBitCount
<= 8)
270 UINT elm_size
= coloruse
== DIB_PAL_COLORS
? sizeof(WORD
) : sizeof(DWORD
);
271 UINT colours
= dst
->biClrUsed
;
273 /* Windows never truncates colour tables, even if they are
274 * unnecessarily big (> 1<<bpp). We emulate this behaviour. */
276 if (colours
> UINT_MAX
/ elm_size
)
278 WARN( "too many colours in palette (%u > %u)\n",
279 colours
, UINT_MAX
/ elm_size
);
283 colour_table_size
= colours
* elm_size
;
286 *bmi_size
= sizeof(BITMAPINFOHEADER
) + colour_table_size
;
287 if (*bmi_size
< sizeof(BITMAPINFOHEADER
))
290 if (dst
->biCompression
== BI_RGB
|| dst
->biCompression
== BI_BITFIELDS
)
291 *img_size
= get_dib_stride( dst
->biWidth
, dst
->biBitCount
) * abs( dst
->biHeight
);
293 *img_size
= dst
->biSizeImage
;
298 static void emf_copy_colours_from_user_bitmapinfo( BITMAPINFO
*dst
, const BITMAPINFO
*info
, UINT coloruse
)
300 if (dst
->bmiHeader
.biCompression
== BI_BITFIELDS
)
302 /* bitfields are always at bmiColors even in larger structures */
303 memcpy( dst
->bmiColors
, info
->bmiColors
, 3 * sizeof(DWORD
) );
305 else if (dst
->bmiHeader
.biBitCount
<= 8)
307 void *src_colors
= (char *)info
+ info
->bmiHeader
.biSize
;
308 unsigned int colors
= dst
->bmiHeader
.biClrUsed
;
310 if (!colors
) colors
= 1 << dst
->bmiHeader
.biBitCount
;
312 if (coloruse
== DIB_PAL_COLORS
)
314 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(WORD
) );
316 else if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
318 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(RGBQUAD
) );
323 RGBTRIPLE
*triple
= (RGBTRIPLE
*)src_colors
;
324 for (i
= 0; i
< colors
; i
++)
326 dst
->bmiColors
[i
].rgbRed
= triple
[i
].rgbtRed
;
327 dst
->bmiColors
[i
].rgbGreen
= triple
[i
].rgbtGreen
;
328 dst
->bmiColors
[i
].rgbBlue
= triple
[i
].rgbtBlue
;
329 dst
->bmiColors
[i
].rgbReserved
= 0;
335 static UINT
emfdc_add_handle( struct emf
*emf
, HGDIOBJ obj
)
339 for (index
= 0; index
< emf
->handles_size
; index
++)
340 if (emf
->handles
[index
] == 0) break;
342 if (index
== emf
->handles_size
)
344 emf
->handles_size
+= HANDLE_LIST_INC
;
345 emf
->handles
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
347 emf
->handles_size
* sizeof(emf
->handles
[0]) );
349 emf
->handles
[index
] = obj
;
352 if (emf
->cur_handles
> emf
->emh
->nHandles
)
353 emf
->emh
->nHandles
++;
355 return index
+ 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
358 static UINT
emfdc_find_object( struct emf
*emf
, HGDIOBJ obj
)
362 for (index
= 0; index
< emf
->handles_size
; index
++)
363 if (emf
->handles
[index
] == obj
) return index
+ 1;
368 static void emfdc_delete_object( HDC hdc
, HGDIOBJ obj
)
370 DC_ATTR
*dc_attr
= get_dc_attr( hdc
);
371 struct emf
*emf
= dc_attr
->emf
;
375 if(!(index
= emfdc_find_object( emf
, obj
))) return;
377 emr
.emr
.iType
= EMR_DELETEOBJECT
;
378 emr
.emr
.nSize
= sizeof(emr
);
379 emr
.ihObject
= index
;
381 emfdc_record( emf
, &emr
.emr
);
383 emf
->handles
[index
- 1] = 0;
387 static DWORD
emfdc_create_brush( struct emf
*emf
, HBRUSH brush
)
392 if (!GetObjectA( brush
, sizeof(logbrush
), &logbrush
)) return 0;
394 switch (logbrush
.lbStyle
) {
399 EMRCREATEBRUSHINDIRECT emr
;
400 emr
.emr
.iType
= EMR_CREATEBRUSHINDIRECT
;
401 emr
.emr
.nSize
= sizeof(emr
);
402 emr
.ihBrush
= index
= emfdc_add_handle( emf
, brush
);
403 emr
.lb
.lbStyle
= logbrush
.lbStyle
;
404 emr
.lb
.lbColor
= logbrush
.lbColor
;
405 emr
.lb
.lbHatch
= logbrush
.lbHatch
;
407 if(!emfdc_record( emf
, &emr
.emr
))
414 EMRCREATEDIBPATTERNBRUSHPT
*emr
;
415 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
416 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
420 if (!__wine_get_brush_bitmap_info( brush
, info
, NULL
, &usage
)) break;
421 info_size
= get_dib_info_size( info
, usage
);
423 emr
= HeapAlloc( GetProcessHeap(), 0,
424 sizeof(EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
) +
425 info_size
+info
->bmiHeader
.biSizeImage
);
428 /* FIXME: There is an extra DWORD written by native before the BMI.
429 * Not sure what it's meant to contain.
431 emr
->offBmi
= sizeof( EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
);
432 *(DWORD
*)(emr
+ 1) = 0x20000000;
434 if (logbrush
.lbStyle
== BS_PATTERN
&& info
->bmiHeader
.biBitCount
== 1)
436 /* Presumably to reduce the size of the written EMF, MS supports an
437 * undocumented iUsage value of 2, indicating a mono bitmap without the
438 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
439 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
440 * irrelevant/constant for monochrome bitmaps.
441 * FIXME: It may be that the DIB functions themselves accept this value.
443 emr
->emr
.iType
= EMR_CREATEMONOBRUSH
;
444 usage
= DIB_PAL_MONO
;
445 emr
->cbBmi
= sizeof( BITMAPINFOHEADER
);
449 emr
->emr
.iType
= EMR_CREATEDIBPATTERNBRUSHPT
;
450 emr
->cbBmi
= info_size
;
452 emr
->ihBrush
= index
= emfdc_add_handle( emf
, brush
);
454 emr
->offBits
= emr
->offBmi
+ emr
->cbBmi
;
455 emr
->cbBits
= info
->bmiHeader
.biSizeImage
;
456 emr
->emr
.nSize
= emr
->offBits
+ emr
->cbBits
;
458 if (info
->bmiHeader
.biClrUsed
== 1 << info
->bmiHeader
.biBitCount
)
459 info
->bmiHeader
.biClrUsed
= 0;
460 memcpy( (BYTE
*)emr
+ emr
->offBmi
, info
, emr
->cbBmi
);
461 __wine_get_brush_bitmap_info( brush
, NULL
, (char *)emr
+ emr
->offBits
, NULL
);
463 if (!emfdc_record( emf
, &emr
->emr
)) index
= 0;
464 HeapFree( GetProcessHeap(), 0, emr
);
469 FIXME("Unknown style %x\n", logbrush
.lbStyle
);
476 static BOOL
emfdc_select_brush( DC_ATTR
*dc_attr
, HBRUSH brush
)
478 struct emf
*emf
= dc_attr
->emf
;
483 /* If the object is a stock brush object, do not need to create it.
484 * See definitions in wingdi.h for range of stock brushes.
485 * We do however have to handle setting the higher order bit to
486 * designate that this is a stock object.
488 for (i
= WHITE_BRUSH
; i
<= DC_BRUSH
; i
++)
490 if (brush
== GetStockObject(i
))
492 index
= i
| 0x80000000;
497 if (!index
&& !(index
= emfdc_find_object( emf
, brush
)))
499 if (!(index
= emfdc_create_brush( emf
, brush
))) return 0;
500 GDI_hdc_using_object( brush
, dc_attr
->hdc
, emfdc_delete_object
);
503 emr
.emr
.iType
= EMR_SELECTOBJECT
;
504 emr
.emr
.nSize
= sizeof(emr
);
505 emr
.ihObject
= index
;
506 return emfdc_record( emf
, &emr
.emr
);
509 static BOOL
emfdc_create_font( struct emf
*emf
, HFONT font
)
512 EMREXTCREATEFONTINDIRECTW emr
;
515 if (!GetObjectW( font
, sizeof(emr
.elfw
.elfLogFont
), &emr
.elfw
.elfLogFont
)) return FALSE
;
517 emr
.emr
.iType
= EMR_EXTCREATEFONTINDIRECTW
;
518 emr
.emr
.nSize
= (sizeof(emr
) + 3) / 4 * 4;
519 emr
.ihFont
= index
= emfdc_add_handle( emf
, font
);
520 emr
.elfw
.elfFullName
[0] = '\0';
521 emr
.elfw
.elfStyle
[0] = '\0';
522 emr
.elfw
.elfVersion
= 0;
523 emr
.elfw
.elfStyleSize
= 0;
524 emr
.elfw
.elfMatch
= 0;
525 emr
.elfw
.elfReserved
= 0;
526 for (i
= 0; i
< ELF_VENDOR_SIZE
; i
++)
527 emr
.elfw
.elfVendorId
[i
] = 0;
528 emr
.elfw
.elfCulture
= PAN_CULTURE_LATIN
;
529 emr
.elfw
.elfPanose
.bFamilyType
= PAN_NO_FIT
;
530 emr
.elfw
.elfPanose
.bSerifStyle
= PAN_NO_FIT
;
531 emr
.elfw
.elfPanose
.bWeight
= PAN_NO_FIT
;
532 emr
.elfw
.elfPanose
.bProportion
= PAN_NO_FIT
;
533 emr
.elfw
.elfPanose
.bContrast
= PAN_NO_FIT
;
534 emr
.elfw
.elfPanose
.bStrokeVariation
= PAN_NO_FIT
;
535 emr
.elfw
.elfPanose
.bArmStyle
= PAN_NO_FIT
;
536 emr
.elfw
.elfPanose
.bLetterform
= PAN_NO_FIT
;
537 emr
.elfw
.elfPanose
.bMidline
= PAN_NO_FIT
;
538 emr
.elfw
.elfPanose
.bXHeight
= PAN_NO_FIT
;
540 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
543 static BOOL
emfdc_select_font( DC_ATTR
*dc_attr
, HFONT font
)
545 struct emf
*emf
= dc_attr
->emf
;
550 /* If the object is a stock font object, do not need to create it.
551 * See definitions in wingdi.h for range of stock fonts.
552 * We do however have to handle setting the higher order bit to
553 * designate that this is a stock object.
556 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
558 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
))
560 index
= i
| 0x80000000;
565 if (!(index
= emfdc_find_object( emf
, font
)))
567 if (!(index
= emfdc_create_font( emf
, font
))) return FALSE
;
568 GDI_hdc_using_object( font
, dc_attr
->hdc
, emfdc_delete_object
);
572 emr
.emr
.iType
= EMR_SELECTOBJECT
;
573 emr
.emr
.nSize
= sizeof(emr
);
574 emr
.ihObject
= index
;
575 return emfdc_record( emf
, &emr
.emr
);
578 static DWORD
emfdc_create_pen( struct emf
*emf
, HPEN hPen
)
583 if (!GetObjectW( hPen
, sizeof(emr
.lopn
), &emr
.lopn
))
585 /* must be an extended pen */
587 INT size
= GetObjectW( hPen
, 0, NULL
);
591 elp
= HeapAlloc( GetProcessHeap(), 0, size
);
593 GetObjectW( hPen
, size
, elp
);
594 /* FIXME: add support for user style pens */
595 emr
.lopn
.lopnStyle
= elp
->elpPenStyle
;
596 emr
.lopn
.lopnWidth
.x
= elp
->elpWidth
;
597 emr
.lopn
.lopnWidth
.y
= 0;
598 emr
.lopn
.lopnColor
= elp
->elpColor
;
600 HeapFree( GetProcessHeap(), 0, elp
);
603 emr
.emr
.iType
= EMR_CREATEPEN
;
604 emr
.emr
.nSize
= sizeof(emr
);
605 emr
.ihPen
= index
= emfdc_add_handle( emf
, hPen
);
606 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
609 static BOOL
emfdc_select_pen( DC_ATTR
*dc_attr
, HPEN pen
)
611 struct emf
*emf
= dc_attr
->emf
;
616 /* If the object is a stock pen object, do not need to create it.
617 * See definitions in wingdi.h for range of stock pens.
618 * We do however have to handle setting the higher order bit to
619 * designate that this is a stock object.
622 for (i
= WHITE_PEN
; i
<= DC_PEN
; i
++)
624 if (pen
== GetStockObject(i
))
626 index
= i
| 0x80000000;
630 if (!index
&& !(index
= emfdc_find_object( emf
, pen
)))
632 if (!(index
= emfdc_create_pen( emf
, pen
))) return FALSE
;
633 GDI_hdc_using_object( pen
, dc_attr
->hdc
, emfdc_delete_object
);
636 emr
.emr
.iType
= EMR_SELECTOBJECT
;
637 emr
.emr
.nSize
= sizeof(emr
);
638 emr
.ihObject
= index
;
639 return emfdc_record( emf
, &emr
.emr
);
642 static DWORD
emfdc_create_palette( struct emf
*emf
, HPALETTE hPal
)
646 EMRCREATEPALETTE hdr
;
647 PALETTEENTRY entry
[255];
650 memset( &pal
, 0, sizeof(pal
) );
652 if (!GetObjectW( hPal
, sizeof(pal
.hdr
.lgpl
) + sizeof(pal
.entry
), &pal
.hdr
.lgpl
))
655 for (i
= 0; i
< pal
.hdr
.lgpl
.palNumEntries
; i
++)
656 pal
.hdr
.lgpl
.palPalEntry
[i
].peFlags
= 0;
658 pal
.hdr
.emr
.iType
= EMR_CREATEPALETTE
;
659 pal
.hdr
.emr
.nSize
= sizeof(pal
.hdr
) + pal
.hdr
.lgpl
.palNumEntries
* sizeof(PALETTEENTRY
);
660 pal
.hdr
.ihPal
= emfdc_add_handle( emf
, hPal
);
662 if (!emfdc_record( emf
, &pal
.hdr
.emr
))
664 return pal
.hdr
.ihPal
;
667 BOOL
EMFDC_SelectPalette( DC_ATTR
*dc_attr
, HPALETTE palette
)
669 struct emf
*emf
= dc_attr
->emf
;
670 EMRSELECTPALETTE emr
;
673 if (palette
== GetStockObject( DEFAULT_PALETTE
))
675 index
= DEFAULT_PALETTE
| 0x80000000;
677 else if (!(index
= emfdc_find_object( emf
, palette
)))
679 if (!(index
= emfdc_create_palette( emf
, palette
))) return 0;
680 GDI_hdc_using_object( palette
, dc_attr
->hdc
, emfdc_delete_object
);
683 emr
.emr
.iType
= EMR_SELECTPALETTE
;
684 emr
.emr
.nSize
= sizeof(emr
);
686 return emfdc_record( emf
, &emr
.emr
);
689 BOOL
EMFDC_SelectObject( DC_ATTR
*dc_attr
, HGDIOBJ obj
)
691 switch (gdi_handle_type( obj
))
693 case NTGDI_OBJ_BRUSH
:
694 return emfdc_select_brush( dc_attr
, obj
);
696 return emfdc_select_font( dc_attr
, obj
);
698 case NTGDI_OBJ_EXTPEN
:
699 return emfdc_select_pen( dc_attr
, obj
);
705 /* determine if we can use 16-bit points to store all the input points */
706 static BOOL
can_use_short_points( const POINT
*pts
, UINT count
)
710 for (i
= 0; i
< count
; i
++)
711 if (((pts
[i
].x
+ 0x8000) & ~0xffff) || ((pts
[i
].y
+ 0x8000) & ~0xffff))
716 /* store points in either long or short format; return a pointer to the end of the stored data */
717 static void *store_points( POINTL
*dest
, const POINT
*pts
, UINT count
, BOOL short_points
)
722 POINTS
*dest_short
= (POINTS
*)dest
;
724 for (i
= 0; i
< count
; i
++)
726 dest_short
[i
].x
= pts
[i
].x
;
727 dest_short
[i
].y
= pts
[i
].y
;
729 return dest_short
+ count
;
733 memcpy( dest
, pts
, count
* sizeof(*dest
) );
738 /* compute the bounds of an array of points, optionally including the current position */
739 static void get_points_bounds( RECTL
*bounds
, const POINT
*pts
, UINT count
, DC_ATTR
*dc_attr
)
745 bounds
->left
= bounds
->right
= dc_attr
->cur_pos
.x
;
746 bounds
->top
= bounds
->bottom
= dc_attr
->cur_pos
.y
;
750 bounds
->left
= bounds
->right
= pts
[0].x
;
751 bounds
->top
= bounds
->bottom
= pts
[0].y
;
753 else *bounds
= empty_bounds
;
755 for (i
= 0; i
< count
; i
++)
757 bounds
->left
= min( bounds
->left
, pts
[i
].x
);
758 bounds
->right
= max( bounds
->right
, pts
[i
].x
);
759 bounds
->top
= min( bounds
->top
, pts
[i
].y
);
760 bounds
->bottom
= max( bounds
->bottom
, pts
[i
].y
);
764 /* helper for path stroke and fill functions */
765 static BOOL
emfdrv_stroke_and_fill_path( struct emf
*emf
, INT type
)
767 EMRSTROKEANDFILLPATH emr
;
770 emr
.emr
.iType
= type
;
771 emr
.emr
.nSize
= sizeof(emr
);
772 emr
.rclBounds
= empty_bounds
;
774 if ((region
= NtGdiPathToRegion( emf
->dc_attr
->hdc
)))
776 NtGdiGetRgnBox( region
, (RECT
*)&emr
.rclBounds
);
777 DeleteObject( region
);
780 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
781 if (!region
) return FALSE
;
782 emfdc_update_bounds( emf
, &emr
.rclBounds
);
786 BOOL
EMFDC_MoveTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
788 struct emf
*emf
= dc_attr
->emf
;
791 emr
.emr
.iType
= EMR_MOVETOEX
;
792 emr
.emr
.nSize
= sizeof(emr
);
795 return emfdc_record( emf
, &emr
.emr
);
798 BOOL
EMFDC_LineTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
802 emr
.emr
.iType
= EMR_LINETO
;
803 emr
.emr
.nSize
= sizeof(emr
);
806 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
809 BOOL
EMFDC_ArcChordPie( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
,
810 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD type
)
812 struct emf
*emf
= dc_attr
->emf
;
816 if (left
== right
|| top
== bottom
) return FALSE
;
818 if (left
> right
) { temp
= left
; left
= right
; right
= temp
; }
819 if (top
> bottom
) { temp
= top
; top
= bottom
; bottom
= temp
; }
821 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
827 emr
.emr
.iType
= type
;
828 emr
.emr
.nSize
= sizeof(emr
);
829 emr
.rclBox
.left
= left
;
830 emr
.rclBox
.top
= top
;
831 emr
.rclBox
.right
= right
;
832 emr
.rclBox
.bottom
= bottom
;
833 emr
.ptlStart
.x
= xstart
;
834 emr
.ptlStart
.y
= ystart
;
837 return emfdc_record( emf
, &emr
.emr
);
840 BOOL
EMFDC_AngleArc( DC_ATTR
*dc_attr
, INT x
, INT y
, DWORD radius
, FLOAT start
, FLOAT sweep
)
844 emr
.emr
.iType
= EMR_ANGLEARC
;
845 emr
.emr
.nSize
= sizeof( emr
);
848 emr
.nRadius
= radius
;
849 emr
.eStartAngle
= start
;
850 emr
.eSweepAngle
= sweep
;
851 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
854 BOOL
EMFDC_Ellipse( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
856 struct emf
*emf
= dc_attr
->emf
;
859 if (left
== right
|| top
== bottom
) return FALSE
;
861 emr
.emr
.iType
= EMR_ELLIPSE
;
862 emr
.emr
.nSize
= sizeof(emr
);
863 emr
.rclBox
.left
= min( left
, right
);
864 emr
.rclBox
.top
= min( top
, bottom
);
865 emr
.rclBox
.right
= max( left
, right
);
866 emr
.rclBox
.bottom
= max( top
, bottom
);
867 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
872 return emfdc_record( emf
, &emr
.emr
);
875 BOOL
EMFDC_Rectangle( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
877 struct emf
*emf
= dc_attr
->emf
;
880 if(left
== right
|| top
== bottom
) return FALSE
;
882 emr
.emr
.iType
= EMR_RECTANGLE
;
883 emr
.emr
.nSize
= sizeof(emr
);
884 emr
.rclBox
.left
= min( left
, right
);
885 emr
.rclBox
.top
= min( top
, bottom
);
886 emr
.rclBox
.right
= max( left
, right
);
887 emr
.rclBox
.bottom
= max( top
, bottom
);
888 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
893 return emfdc_record( emf
, &emr
.emr
);
896 BOOL
EMFDC_RoundRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
,
897 INT bottom
, INT ell_width
, INT ell_height
)
899 struct emf
*emf
= dc_attr
->emf
;
902 if (left
== right
|| top
== bottom
) return FALSE
;
904 emr
.emr
.iType
= EMR_ROUNDRECT
;
905 emr
.emr
.nSize
= sizeof(emr
);
906 emr
.rclBox
.left
= min( left
, right
);
907 emr
.rclBox
.top
= min( top
, bottom
);
908 emr
.rclBox
.right
= max( left
, right
);
909 emr
.rclBox
.bottom
= max( top
, bottom
);
910 emr
.szlCorner
.cx
= ell_width
;
911 emr
.szlCorner
.cy
= ell_height
;
912 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
917 return emfdc_record( emf
, &emr
.emr
);
920 BOOL
EMFDC_SetPixel( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
)
924 emr
.emr
.iType
= EMR_SETPIXELV
;
925 emr
.emr
.nSize
= sizeof(emr
);
929 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
932 static BOOL
emfdc_polylinegon( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
, DWORD type
)
934 struct emf
*emf
= dc_attr
->emf
;
937 BOOL ret
, use_small_emr
= can_use_short_points( points
, count
);
939 size
= use_small_emr
? offsetof( EMRPOLYLINE16
, apts
[count
] ) : offsetof( EMRPOLYLINE
, aptl
[count
] );
941 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
942 emr
->emr
.iType
= use_small_emr
? type
+ EMR_POLYLINE16
- EMR_POLYLINE
: type
;
943 emr
->emr
.nSize
= size
;
946 store_points( emr
->aptl
, points
, count
, use_small_emr
);
949 get_points_bounds( &emr
->rclBounds
, points
, count
,
950 (type
== EMR_POLYBEZIERTO
|| type
== EMR_POLYLINETO
) ? dc_attr
: 0 );
952 emr
->rclBounds
= empty_bounds
;
954 ret
= emfdc_record( emf
, &emr
->emr
);
955 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
956 HeapFree( GetProcessHeap(), 0, emr
);
960 BOOL
EMFDC_Polyline( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
962 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINE
);
965 BOOL
EMFDC_PolylineTo( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
967 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINETO
);
970 BOOL
EMFDC_Polygon( DC_ATTR
*dc_attr
, const POINT
*pt
, INT count
)
972 if(count
< 2) return FALSE
;
973 return emfdc_polylinegon( dc_attr
, pt
, count
, EMR_POLYGON
);
976 BOOL
EMFDC_PolyBezier( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
978 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIER
);
981 BOOL
EMFDC_PolyBezierTo( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
983 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIERTO
);
986 static BOOL
emfdc_poly_polylinegon( struct emf
*emf
, const POINT
*pt
, const INT
*counts
,
987 UINT polys
, DWORD type
)
989 EMRPOLYPOLYLINE
*emr
;
990 DWORD cptl
= 0, poly
, size
;
991 BOOL ret
, use_small_emr
, bounds_valid
= TRUE
;
993 for(poly
= 0; poly
< polys
; poly
++) {
994 cptl
+= counts
[poly
];
995 if(counts
[poly
] < 2) bounds_valid
= FALSE
;
997 if(!cptl
) bounds_valid
= FALSE
;
998 use_small_emr
= can_use_short_points( pt
, cptl
);
1000 size
= FIELD_OFFSET(EMRPOLYPOLYLINE
, aPolyCounts
[polys
]);
1002 size
+= cptl
* sizeof(POINTS
);
1004 size
+= cptl
* sizeof(POINTL
);
1006 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1008 emr
->emr
.iType
= type
;
1009 if(use_small_emr
) emr
->emr
.iType
+= EMR_POLYPOLYLINE16
- EMR_POLYPOLYLINE
;
1011 emr
->emr
.nSize
= size
;
1012 if(bounds_valid
&& !emf
->path
)
1013 get_points_bounds( &emr
->rclBounds
, pt
, cptl
, 0 );
1015 emr
->rclBounds
= empty_bounds
;
1016 emr
->nPolys
= polys
;
1021 memcpy( emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
) );
1022 store_points( (POINTL
*)(emr
->aPolyCounts
+ polys
), pt
, cptl
, use_small_emr
);
1025 ret
= emfdc_record( emf
, &emr
->emr
);
1026 if(ret
&& !bounds_valid
)
1029 SetLastError( ERROR_INVALID_PARAMETER
);
1031 if(ret
&& !emf
->path
)
1032 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1033 HeapFree( GetProcessHeap(), 0, emr
);
1037 BOOL
EMFDC_PolyPolyline( DC_ATTR
*dc_attr
, const POINT
*pt
, const DWORD
*counts
, DWORD polys
)
1039 return emfdc_poly_polylinegon( dc_attr
->emf
, pt
, (const INT
*)counts
, polys
, EMR_POLYPOLYLINE
);
1042 BOOL
EMFDC_PolyPolygon( DC_ATTR
*dc_attr
, const POINT
*pt
, const INT
*counts
, UINT polys
)
1044 return emfdc_poly_polylinegon( dc_attr
->emf
, pt
, counts
, polys
, EMR_POLYPOLYGON
);
1047 BOOL
EMFDC_PolyDraw( DC_ATTR
*dc_attr
, const POINT
*pts
, const BYTE
*types
, DWORD count
)
1049 struct emf
*emf
= dc_attr
->emf
;
1053 BOOL use_small_emr
= can_use_short_points( pts
, count
);
1056 size
= use_small_emr
? offsetof( EMRPOLYDRAW16
, apts
[count
] )
1057 : offsetof( EMRPOLYDRAW
, aptl
[count
] );
1058 size
+= (count
+ 3) & ~3;
1060 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1062 emr
->emr
.iType
= use_small_emr
? EMR_POLYDRAW16
: EMR_POLYDRAW
;
1063 emr
->emr
.nSize
= size
;
1066 types_dest
= store_points( emr
->aptl
, pts
, count
, use_small_emr
);
1067 memcpy( types_dest
, types
, count
);
1068 if (count
& 3) memset( types_dest
+ count
, 0, 4 - (count
& 3) );
1071 get_points_bounds( &emr
->rclBounds
, pts
, count
, 0 );
1073 emr
->rclBounds
= empty_bounds
;
1075 ret
= emfdc_record( emf
, &emr
->emr
);
1076 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1077 HeapFree( GetProcessHeap(), 0, emr
);
1081 BOOL
EMFDC_ExtFloodFill( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
, UINT fill_type
)
1083 EMREXTFLOODFILL emr
;
1085 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
1086 emr
.emr
.nSize
= sizeof(emr
);
1089 emr
.crColor
= color
;
1090 emr
.iMode
= fill_type
;
1091 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1094 BOOL
EMFDC_FillRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
)
1096 struct emf
*emf
= dc_attr
->emf
;
1098 DWORD size
, rgnsize
, index
;
1101 if (!(index
= emfdc_create_brush( emf
, hbrush
))) return FALSE
;
1103 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1104 size
= rgnsize
+ offsetof(EMRFILLRGN
,RgnData
);
1105 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1107 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1109 emr
->emr
.iType
= EMR_FILLRGN
;
1110 emr
->emr
.nSize
= size
;
1111 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1112 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1113 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1114 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1115 emr
->cbRgnData
= rgnsize
;
1116 emr
->ihBrush
= index
;
1118 ret
= emfdc_record( emf
, &emr
->emr
);
1119 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1120 HeapFree( GetProcessHeap(), 0, emr
);
1124 BOOL
EMFDC_FrameRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
1126 struct emf
*emf
= dc_attr
->emf
;
1128 DWORD size
, rgnsize
, index
;
1131 index
= emfdc_create_brush( emf
, hbrush
);
1132 if(!index
) return FALSE
;
1134 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1135 size
= rgnsize
+ offsetof(EMRFRAMERGN
,RgnData
);
1136 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1138 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1140 emr
->emr
.iType
= EMR_FRAMERGN
;
1141 emr
->emr
.nSize
= size
;
1142 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1143 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1144 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1145 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1146 emr
->cbRgnData
= rgnsize
;
1147 emr
->ihBrush
= index
;
1148 emr
->szlStroke
.cx
= width
;
1149 emr
->szlStroke
.cy
= height
;
1151 ret
= emfdc_record( emf
, &emr
->emr
);
1152 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1153 HeapFree( GetProcessHeap(), 0, emr
);
1157 static BOOL
emfdc_paint_invert_region( struct emf
*emf
, HRGN hrgn
, DWORD iType
)
1160 DWORD size
, rgnsize
;
1163 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1164 size
= rgnsize
+ offsetof(EMRINVERTRGN
,RgnData
);
1165 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1167 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1169 emr
->emr
.iType
= iType
;
1170 emr
->emr
.nSize
= size
;
1171 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1172 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1173 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1174 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1175 emr
->cbRgnData
= rgnsize
;
1177 ret
= emfdc_record( emf
, &emr
->emr
);
1178 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1179 HeapFree( GetProcessHeap(), 0, emr
);
1183 BOOL
EMFDC_PaintRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1185 return emfdc_paint_invert_region( dc_attr
->emf
, hrgn
, EMR_PAINTRGN
);
1188 BOOL
EMFDC_InvertRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1190 return emfdc_paint_invert_region( dc_attr
->emf
, hrgn
, EMR_INVERTRGN
);
1193 BOOL
EMFDC_ExtTextOut( DC_ATTR
*dc_attr
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1194 const WCHAR
*str
, UINT count
, const INT
*dx
)
1196 struct emf
*emf
= dc_attr
->emf
;
1197 FLOAT ex_scale
, ey_scale
;
1198 EMREXTTEXTOUTW
*emr
;
1199 int text_height
= 0;
1205 size
= sizeof(*emr
) + ((count
+1) & ~1) * sizeof(WCHAR
) + count
* sizeof(INT
);
1207 TRACE( "%s %s count %d size = %d\n", debugstr_wn(str
, count
),
1208 wine_dbgstr_rect(rect
), count
, size
);
1209 emr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1211 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1213 const INT horzSize
= GetDeviceCaps( dc_attr
->hdc
, HORZSIZE
);
1214 const INT horzRes
= GetDeviceCaps( dc_attr
->hdc
, HORZRES
);
1215 const INT vertSize
= GetDeviceCaps( dc_attr
->hdc
, VERTSIZE
);
1216 const INT vertRes
= GetDeviceCaps( dc_attr
->hdc
, VERTRES
);
1217 SIZE wndext
, vportext
;
1219 GetViewportExtEx( dc_attr
->hdc
, &vportext
);
1220 GetWindowExtEx( dc_attr
->hdc
, &wndext
);
1221 ex_scale
= 100.0 * ((FLOAT
)horzSize
/ (FLOAT
)horzRes
) /
1222 ((FLOAT
)wndext
.cx
/ (FLOAT
)vportext
.cx
);
1223 ey_scale
= 100.0 * ((FLOAT
)vertSize
/ (FLOAT
)vertRes
) /
1224 ((FLOAT
)wndext
.cy
/ (FLOAT
)vportext
.cy
);
1232 emr
->emr
.iType
= EMR_EXTTEXTOUTW
;
1233 emr
->emr
.nSize
= size
;
1234 emr
->iGraphicsMode
= dc_attr
->graphics_mode
;
1235 emr
->exScale
= ex_scale
;
1236 emr
->eyScale
= ey_scale
;
1237 emr
->emrtext
.ptlReference
.x
= x
;
1238 emr
->emrtext
.ptlReference
.y
= y
;
1239 emr
->emrtext
.nChars
= count
;
1240 emr
->emrtext
.offString
= sizeof(*emr
);
1241 memcpy( (char*)emr
+ emr
->emrtext
.offString
, str
, count
* sizeof(WCHAR
) );
1242 emr
->emrtext
.fOptions
= flags
;
1245 emr
->emrtext
.rcl
.left
= emr
->emrtext
.rcl
.top
= 0;
1246 emr
->emrtext
.rcl
.right
= emr
->emrtext
.rcl
.bottom
= -1;
1250 emr
->emrtext
.rcl
.left
= rect
->left
;
1251 emr
->emrtext
.rcl
.top
= rect
->top
;
1252 emr
->emrtext
.rcl
.right
= rect
->right
;
1253 emr
->emrtext
.rcl
.bottom
= rect
->bottom
;
1256 emr
->emrtext
.offDx
= emr
->emrtext
.offString
+ ((count
+1) & ~1) * sizeof(WCHAR
);
1261 memcpy( (char*)emr
+ emr
->emrtext
.offDx
, dx
, count
* sizeof(INT
) );
1262 for (i
= 0; i
< count
; i
++) text_width
+= dx
[i
];
1263 if (GetTextExtentPoint32W( dc_attr
->hdc
, str
, count
, &str_size
))
1264 text_height
= str_size
.cy
;
1269 INT
*emf_dx
= (INT
*)((char*)emr
+ emr
->emrtext
.offDx
);
1271 for (i
= 0; i
< count
; i
++)
1273 if (GetTextExtentPoint32W( dc_attr
->hdc
, str
+ i
, 1, &charSize
))
1275 emf_dx
[i
] = charSize
.cx
;
1276 text_width
+= charSize
.cx
;
1277 text_height
= max( text_height
, charSize
.cy
);
1284 emr
->rclBounds
.left
= emr
->rclBounds
.top
= 0;
1285 emr
->rclBounds
.right
= emr
->rclBounds
.bottom
= -1;
1289 /* FIXME: handle font escapement */
1290 switch (dc_attr
->text_align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1293 emr
->rclBounds
.left
= x
- (text_width
/ 2) - 1;
1294 emr
->rclBounds
.right
= x
+ (text_width
/ 2) + 1;
1298 emr
->rclBounds
.left
= x
- text_width
- 1;
1299 emr
->rclBounds
.right
= x
;
1302 default: /* TA_LEFT */
1303 emr
->rclBounds
.left
= x
;
1304 emr
->rclBounds
.right
= x
+ text_width
+ 1;
1307 switch (dc_attr
->text_align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1310 if (!GetTextMetricsW( dc_attr
->hdc
, &tm
)) tm
.tmDescent
= 0;
1311 /* Play safe here... it's better to have a bounding box */
1312 /* that is too big than too small. */
1313 emr
->rclBounds
.top
= y
- text_height
- 1;
1314 emr
->rclBounds
.bottom
= y
+ tm
.tmDescent
+ 1;
1318 emr
->rclBounds
.top
= y
- text_height
- 1;
1319 emr
->rclBounds
.bottom
= y
;
1322 default: /* TA_TOP */
1323 emr
->rclBounds
.top
= y
;
1324 emr
->rclBounds
.bottom
= y
+ text_height
+ 1;
1326 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1329 ret
= emfdc_record( emf
, &emr
->emr
);
1330 HeapFree( GetProcessHeap(), 0, emr
);
1334 BOOL
EMFDC_GradientFill( DC_ATTR
*dc_attr
, TRIVERTEX
*vert_array
, ULONG nvert
,
1335 void *grad_array
, ULONG ngrad
, ULONG mode
)
1337 EMRGRADIENTFILL
*emr
;
1338 ULONG i
, pt
, size
, num_pts
= ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2);
1339 const ULONG
*pts
= (const ULONG
*)grad_array
;
1342 size
= FIELD_OFFSET(EMRGRADIENTFILL
, Ver
[nvert
]) + num_pts
* sizeof(pts
[0]);
1344 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1345 if (!emr
) return FALSE
;
1347 for (i
= 0; i
< num_pts
; i
++)
1353 emr
->rclBounds
.left
= emr
->rclBounds
.right
= vert_array
[pt
].x
;
1354 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1358 if (vert_array
[pt
].x
< emr
->rclBounds
.left
)
1359 emr
->rclBounds
.left
= vert_array
[pt
].x
;
1360 else if (vert_array
[pt
].x
> emr
->rclBounds
.right
)
1361 emr
->rclBounds
.right
= vert_array
[pt
].x
;
1362 if (vert_array
[pt
].y
< emr
->rclBounds
.top
)
1363 emr
->rclBounds
.top
= vert_array
[pt
].y
;
1364 else if (vert_array
[pt
].y
> emr
->rclBounds
.bottom
)
1365 emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1368 emr
->rclBounds
.right
--;
1369 emr
->rclBounds
.bottom
--;
1371 emr
->emr
.iType
= EMR_GRADIENTFILL
;
1372 emr
->emr
.nSize
= size
;
1376 memcpy( emr
->Ver
, vert_array
, nvert
* sizeof(vert_array
[0]) );
1377 memcpy( emr
->Ver
+ nvert
, pts
, num_pts
* sizeof(pts
[0]) );
1379 emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1380 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
1381 HeapFree( GetProcessHeap(), 0, emr
);
1385 BOOL
EMFDC_FillPath( DC_ATTR
*dc_attr
)
1387 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_FILLPATH
);
1390 BOOL
EMFDC_StrokeAndFillPath( DC_ATTR
*dc_attr
)
1392 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_STROKEANDFILLPATH
);
1395 BOOL
EMFDC_StrokePath( DC_ATTR
*dc_attr
)
1397 return emfdrv_stroke_and_fill_path( dc_attr
->emf
, EMR_STROKEPATH
);
1400 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1401 static BOOL
emfdrv_stretchblt( struct emf
*emf
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1402 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1403 DWORD rop
, DWORD type
)
1405 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1406 UINT bmi_size
, emr_size
, size
;
1407 HBITMAP bitmap
, blit_bitmap
= NULL
;
1408 EMRBITBLT
*emr
= NULL
;
1413 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1416 blit_bitmap
= bitmap
;
1417 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1419 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1420 emr_size
= type
== EMR_BITBLT
? sizeof(EMRBITBLT
) : sizeof(EMRSTRETCHBLT
);
1421 size
= emr_size
+ bmi_size
+ src_info
.bmiHeader
.biSizeImage
;
1423 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1425 emr
->emr
.iType
= type
;
1426 emr
->emr
.nSize
= size
;
1427 emr
->rclBounds
.left
= x_dst
;
1428 emr
->rclBounds
.top
= y_dst
;
1429 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1430 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1433 emr
->cxDest
= width_dst
;
1434 emr
->cyDest
= height_dst
;
1437 if (type
!= EMR_BITBLT
)
1439 EMRSTRETCHBLT
*emr_stretchblt
= (EMRSTRETCHBLT
*)emr
;
1440 emr_stretchblt
->cxSrc
= width_src
;
1441 emr_stretchblt
->cySrc
= height_src
;
1444 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1445 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1446 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1447 emr
->offBmiSrc
= emr_size
;
1448 emr
->cbBmiSrc
= bmi_size
;
1449 emr
->offBitsSrc
= emr_size
+ bmi_size
;
1450 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1452 bmi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1453 bmi
->bmiHeader
= src_info
.bmiHeader
;
1454 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1455 (BYTE
*)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1458 ret
= emfdc_record( emf
, (EMR
*)emr
);
1459 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1463 HeapFree( GetProcessHeap(), 0, emr
);
1464 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1465 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1469 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1470 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1471 BLENDFUNCTION blend_function
)
1473 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
,
1474 x_src
, y_src
, width_src
, height_src
, *(DWORD
*)&blend_function
,
1478 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1480 struct emf
*emf
= dc_attr
->emf
;
1484 emr
.emr
.iType
= EMR_BITBLT
;
1485 emr
.emr
.nSize
= sizeof(emr
);
1486 emr
.rclBounds
.left
= left
;
1487 emr
.rclBounds
.top
= top
;
1488 emr
.rclBounds
.right
= left
+ width
- 1;
1489 emr
.rclBounds
.bottom
= top
+ height
- 1;
1493 emr
.cyDest
= height
;
1497 emr
.xformSrc
.eM11
= 1.0;
1498 emr
.xformSrc
.eM12
= 0.0;
1499 emr
.xformSrc
.eM21
= 0.0;
1500 emr
.xformSrc
.eM22
= 1.0;
1501 emr
.xformSrc
.eDx
= 0.0;
1502 emr
.xformSrc
.eDy
= 0.0;
1503 emr
.crBkColorSrc
= 0;
1510 ret
= emfdc_record( emf
, &emr
.emr
);
1511 if (ret
) emfdc_update_bounds( emf
, &emr
.rclBounds
);
1515 static inline BOOL
rop_uses_src( DWORD rop
)
1517 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
1520 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
1521 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
1523 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
1524 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width
, height
,
1525 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
1528 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1529 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1532 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1533 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
,
1534 hdc_src
, x_src
, y_src
, width_src
,
1535 height_src
, rop
, EMR_STRETCHBLT
);
1538 BOOL
EMFDC_TransparentBlt( DC_ATTR
*dc_attr
, int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1539 HDC hdc_src
, int x_src
, int y_src
, int width_src
, int height_src
,
1542 return emfdrv_stretchblt( dc_attr
->emf
, x_dst
, y_dst
, width_dst
, height_dst
,
1543 hdc_src
, x_src
, y_src
, width_src
,
1544 height_src
, color
, EMR_TRANSPARENTBLT
);
1547 BOOL
EMFDC_MaskBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1548 HDC hdc_src
, INT x_src
, INT y_src
, HBITMAP mask
,
1549 INT x_mask
, INT y_mask
, DWORD rop
)
1551 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1552 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1553 struct emf
*emf
= dc_attr
->emf
;
1554 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1555 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1556 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1557 UINT bmi_size
, size
, mask_info_size
= 0;
1558 EMRMASKBLT
*emr
= NULL
;
1560 HDC blit_dc
, mask_dc
= NULL
;
1563 if (!rop_uses_src( rop
))
1564 return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1566 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1568 blit_bitmap
= bitmap
;
1569 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1575 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1576 if (mask_info
.bmiHeader
.biBitCount
== 1)
1577 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1579 else mask_info
.bmiHeader
.biSizeImage
= 0;
1581 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1582 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1584 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1586 emr
->emr
.iType
= EMR_MASKBLT
;
1587 emr
->emr
.nSize
= size
;
1588 emr
->rclBounds
.left
= x_dst
;
1589 emr
->rclBounds
.top
= y_dst
;
1590 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1591 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1594 emr
->cxDest
= width_dst
;
1595 emr
->cyDest
= height_dst
;
1599 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1600 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1601 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1602 emr
->offBmiSrc
= sizeof(*emr
);
1603 emr
->cbBmiSrc
= bmi_size
;
1604 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1605 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1606 emr
->xMask
= x_mask
;
1607 emr
->yMask
= y_mask
;
1608 emr
->iUsageMask
= DIB_PAL_MONO
;
1609 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1610 emr
->cbBmiMask
= mask_info_size
;
1611 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1612 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1614 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1615 bmi
->bmiHeader
= src_info
.bmiHeader
;
1616 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1617 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1622 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1623 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1624 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1625 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1630 ret
= emfdc_record( emf
, (EMR
*)emr
);
1631 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1635 HeapFree( GetProcessHeap(), 0, emr
);
1636 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1637 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1638 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1639 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1643 BOOL
EMFDC_PlgBlt( DC_ATTR
*dc_attr
, const POINT
*points
, HDC hdc_src
, INT x_src
, INT y_src
,
1644 INT width
, INT height
, HBITMAP mask
, INT x_mask
, INT y_mask
)
1646 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1647 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1648 struct emf
*emf
= dc_attr
->emf
;
1649 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1650 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1651 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1652 UINT bmi_size
, size
, mask_info_size
= 0;
1653 EMRPLGBLT
*emr
= NULL
;
1655 HDC blit_dc
, mask_dc
= NULL
;
1656 int x_min
, y_min
, x_max
, y_max
, i
;
1659 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1662 blit_bitmap
= bitmap
;
1663 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1669 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1670 if (mask_info
.bmiHeader
.biBitCount
== 1)
1671 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1673 else mask_info
.bmiHeader
.biSizeImage
= 0;
1675 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1676 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1678 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1680 emr
->emr
.iType
= EMR_PLGBLT
;
1681 emr
->emr
.nSize
= size
;
1683 /* FIXME: not exactly what native does */
1684 x_min
= x_max
= points
[1].x
+ points
[2].x
- points
[0].x
;
1685 y_min
= y_max
= points
[1].y
+ points
[2].y
- points
[0].y
;
1686 for (i
= 0; i
< ARRAYSIZE(emr
->aptlDest
); i
++)
1688 x_min
= min( x_min
, points
[i
].x
);
1689 y_min
= min( y_min
, points
[i
].y
);
1690 x_max
= max( x_max
, points
[i
].x
);
1691 y_max
= max( y_min
, points
[i
].y
);
1693 emr
->rclBounds
.left
= x_min
;
1694 emr
->rclBounds
.top
= y_min
;
1695 emr
->rclBounds
.right
= x_max
;
1696 emr
->rclBounds
.bottom
= y_max
;
1697 memcpy( emr
->aptlDest
, points
, sizeof(emr
->aptlDest
) );
1701 emr
->cySrc
= height
;
1702 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1703 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1704 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1705 emr
->offBmiSrc
= sizeof(*emr
);
1706 emr
->cbBmiSrc
= bmi_size
;
1707 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1708 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1709 emr
->xMask
= x_mask
;
1710 emr
->yMask
= y_mask
;
1711 emr
->iUsageMask
= DIB_PAL_MONO
;
1712 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1713 emr
->cbBmiMask
= mask_info_size
;
1714 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1715 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1717 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1718 bmi
->bmiHeader
= src_info
.bmiHeader
;
1719 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1720 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1725 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1726 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1727 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1728 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1733 ret
= emfdc_record( emf
, (EMR
*)emr
);
1734 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1738 HeapFree( GetProcessHeap(), 0, emr
);
1739 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1740 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1741 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1742 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1746 BOOL
EMFDC_StretchDIBits( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1747 INT x_src
, INT y_src
, INT width_src
, INT height_src
, const void *bits
,
1748 const BITMAPINFO
*info
, UINT usage
, DWORD rop
)
1750 EMRSTRETCHDIBITS
*emr
;
1752 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1753 BITMAPINFOHEADER bih
;
1756 /* calculate the size of the colour table and the image */
1757 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1758 &bmi_size
, &img_size
)) return 0;
1760 /* check for overflows */
1761 payload_size
= bmi_size
+ img_size
;
1762 if (payload_size
< bmi_size
) return 0;
1764 emr_size
= sizeof (EMRSTRETCHDIBITS
) + payload_size
;
1765 if (emr_size
< sizeof (EMRSTRETCHDIBITS
)) return 0;
1767 /* allocate record */
1768 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
))) return 0;
1770 /* write a bitmap info header (with colours) to the record */
1771 bi
= (BITMAPINFO
*)&emr
[1];
1772 bi
->bmiHeader
= bih
;
1773 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1775 /* write bitmap bits to the record */
1776 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1778 /* fill in the EMR header at the front of our piece of memory */
1779 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
1780 emr
->emr
.nSize
= emr_size
;
1784 emr
->cxDest
= width_dst
;
1785 emr
->cyDest
= height_dst
;
1790 emr
->iUsageSrc
= usage
;
1791 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
1792 emr
->cbBmiSrc
= bmi_size
;
1793 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1794 emr
->cbBitsSrc
= img_size
;
1796 emr
->cxSrc
= width_src
;
1797 emr
->cySrc
= height_src
;
1799 emr
->rclBounds
.left
= x_dst
;
1800 emr
->rclBounds
.top
= y_dst
;
1801 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1802 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1804 /* save the record we just created */
1805 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
1806 if (ret
) emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1807 HeapFree( GetProcessHeap(), 0, emr
);
1811 BOOL
EMFDC_SetDIBitsToDevice( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, DWORD width
, DWORD height
,
1812 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
1813 const void *bits
, const BITMAPINFO
*info
, UINT usage
)
1815 EMRSETDIBITSTODEVICE
*emr
;
1817 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1818 UINT src_height
, stride
;
1819 BITMAPINFOHEADER bih
;
1822 /* calculate the size of the colour table and the image */
1823 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1824 &bmi_size
, &img_size
)) return 0;
1826 if (bih
.biHeight
>= 0)
1828 src_height
= (UINT
)bih
.biHeight
;
1829 if (src_height
> y_src
+ height
) src_height
= y_src
+ height
;
1831 if (src_height
< startscan
) lines
= 0;
1832 else if (lines
> src_height
- startscan
) lines
= src_height
- startscan
;
1834 if (!lines
) return 0;
1836 if (bih
.biCompression
== BI_RGB
|| bih
.biCompression
== BI_BITFIELDS
)
1838 /* truncate image and check for overflows */
1839 stride
= get_dib_stride( bih
.biWidth
, bih
.biBitCount
);
1840 img_size
= lines
* stride
;
1841 if (img_size
/ stride
!= lines
) return 0;
1845 /* check for overflows */
1846 payload_size
= bmi_size
+ img_size
;
1847 if (payload_size
< bmi_size
) return 0;
1849 emr_size
= sizeof (EMRSETDIBITSTODEVICE
) + payload_size
;
1850 if (emr_size
< sizeof (EMRSETDIBITSTODEVICE
)) return 0;
1852 /* allocate record */
1853 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, emr_size
))) return FALSE
;
1855 /* write a bitmap info header (with colours) to the record */
1856 bi
= (BITMAPINFO
*)&emr
[1];
1857 bi
->bmiHeader
= bih
;
1858 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1860 /* write bitmap bits to the record */
1861 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1863 emr
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
1864 emr
->emr
.nSize
= emr_size
;
1865 emr
->rclBounds
.left
= x_dst
;
1866 emr
->rclBounds
.top
= y_dst
;
1867 emr
->rclBounds
.right
= x_dst
+ width
- 1;
1868 emr
->rclBounds
.bottom
= y_dst
+ height
- 1;
1874 emr
->cySrc
= height
;
1875 emr
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
1876 emr
->cbBmiSrc
= bmi_size
;
1877 emr
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + bmi_size
;
1878 emr
->cbBitsSrc
= img_size
;
1879 emr
->iUsageSrc
= usage
;
1880 emr
->iStartScan
= startscan
;
1881 emr
->cScans
= lines
;
1883 if ((ret
= emfdc_record( dc_attr
->emf
, (EMR
*)emr
)))
1884 emfdc_update_bounds( dc_attr
->emf
, &emr
->rclBounds
);
1886 HeapFree( GetProcessHeap(), 0, emr
);
1890 BOOL
EMFDC_SetDCBrushColor( DC_ATTR
*dc_attr
, COLORREF color
)
1892 struct emf
*emf
= dc_attr
->emf
;
1893 EMRSELECTOBJECT emr
;
1896 if (GetCurrentObject( dc_attr
->hdc
, OBJ_BRUSH
) != GetStockObject( DC_BRUSH
)) return TRUE
;
1898 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
1899 if (!(emf
->dc_brush
= CreateSolidBrush( color
))) return FALSE
;
1900 if (!(index
= emfdc_create_brush( emf
, emf
->dc_brush
))) return FALSE
;
1901 GDI_hdc_using_object( emf
->dc_brush
, dc_attr
->hdc
, emfdc_delete_object
);
1902 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1903 emr
.emr
.nSize
= sizeof(emr
);
1904 emr
.ihObject
= index
;
1905 return emfdc_record( emf
, &emr
.emr
);
1908 BOOL
EMFDC_SetDCPenColor( DC_ATTR
*dc_attr
, COLORREF color
)
1910 struct emf
*emf
= dc_attr
->emf
;
1911 EMRSELECTOBJECT emr
;
1913 LOGPEN logpen
= { PS_SOLID
, { 0, 0 }, color
};
1915 if (GetCurrentObject( dc_attr
->hdc
, OBJ_PEN
) != GetStockObject( DC_PEN
)) return TRUE
;
1917 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
1918 if (!(emf
->dc_pen
= CreatePenIndirect( &logpen
))) return FALSE
;
1919 if (!(index
= emfdc_create_pen( emf
, emf
->dc_pen
))) return FALSE
;
1920 GDI_hdc_using_object( emf
->dc_pen
, dc_attr
->hdc
, emfdc_delete_object
);
1921 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1922 emr
.emr
.nSize
= sizeof(emr
);
1923 emr
.ihObject
= index
;
1924 return emfdc_record( emf
, &emr
.emr
);
1927 BOOL
EMFDC_SaveDC( DC_ATTR
*dc_attr
)
1931 emr
.emr
.iType
= EMR_SAVEDC
;
1932 emr
.emr
.nSize
= sizeof(emr
);
1933 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1936 BOOL
EMFDC_RestoreDC( DC_ATTR
*dc_attr
, INT level
)
1940 if (abs(level
) > dc_attr
->save_level
|| level
== 0) return FALSE
;
1942 emr
.emr
.iType
= EMR_RESTOREDC
;
1943 emr
.emr
.nSize
= sizeof(emr
);
1945 emr
.iRelative
= level
;
1947 emr
.iRelative
= level
- dc_attr
->save_level
- 1;
1948 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1951 BOOL
EMFDC_SetTextAlign( DC_ATTR
*dc_attr
, UINT align
)
1953 EMRSETTEXTALIGN emr
;
1955 emr
.emr
.iType
= EMR_SETTEXTALIGN
;
1956 emr
.emr
.nSize
= sizeof(emr
);
1958 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1961 BOOL
EMFDC_SetTextJustification( DC_ATTR
*dc_attr
, INT extra
, INT breaks
)
1963 EMRSETTEXTJUSTIFICATION emr
;
1965 emr
.emr
.iType
= EMR_SETTEXTJUSTIFICATION
;
1966 emr
.emr
.nSize
= sizeof(emr
);
1967 emr
.nBreakExtra
= extra
;
1968 emr
.nBreakCount
= breaks
;
1969 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1972 BOOL
EMFDC_SetBkMode( DC_ATTR
*dc_attr
, INT mode
)
1976 emr
.emr
.iType
= EMR_SETBKMODE
;
1977 emr
.emr
.nSize
= sizeof(emr
);
1979 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1982 BOOL
EMFDC_SetBkColor( DC_ATTR
*dc_attr
, COLORREF color
)
1986 emr
.emr
.iType
= EMR_SETBKCOLOR
;
1987 emr
.emr
.nSize
= sizeof(emr
);
1988 emr
.crColor
= color
;
1989 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
1993 BOOL
EMFDC_SetTextColor( DC_ATTR
*dc_attr
, COLORREF color
)
1995 EMRSETTEXTCOLOR emr
;
1997 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
1998 emr
.emr
.nSize
= sizeof(emr
);
1999 emr
.crColor
= color
;
2000 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2003 BOOL
EMFDC_SetROP2( DC_ATTR
*dc_attr
, INT rop
)
2007 emr
.emr
.iType
= EMR_SETROP2
;
2008 emr
.emr
.nSize
= sizeof(emr
);
2010 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2013 BOOL
EMFDC_SetPolyFillMode( DC_ATTR
*dc_attr
, INT mode
)
2015 EMRSETPOLYFILLMODE emr
;
2017 emr
.emr
.iType
= EMR_SETPOLYFILLMODE
;
2018 emr
.emr
.nSize
= sizeof(emr
);
2020 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2023 BOOL
EMFDC_SetStretchBltMode( DC_ATTR
*dc_attr
, INT mode
)
2025 EMRSETSTRETCHBLTMODE emr
;
2027 emr
.emr
.iType
= EMR_SETSTRETCHBLTMODE
;
2028 emr
.emr
.nSize
= sizeof(emr
);
2030 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2033 BOOL
EMFDC_SetArcDirection( DC_ATTR
*dc_attr
, INT dir
)
2035 EMRSETARCDIRECTION emr
;
2037 emr
.emr
.iType
= EMR_SETARCDIRECTION
;
2038 emr
.emr
.nSize
= sizeof(emr
);
2039 emr
.iArcDirection
= dir
;
2040 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2043 INT
EMFDC_ExcludeClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2045 EMREXCLUDECLIPRECT emr
;
2047 emr
.emr
.iType
= EMR_EXCLUDECLIPRECT
;
2048 emr
.emr
.nSize
= sizeof(emr
);
2049 emr
.rclClip
.left
= left
;
2050 emr
.rclClip
.top
= top
;
2051 emr
.rclClip
.right
= right
;
2052 emr
.rclClip
.bottom
= bottom
;
2053 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2056 BOOL
EMFDC_IntersectClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2058 EMRINTERSECTCLIPRECT emr
;
2060 emr
.emr
.iType
= EMR_INTERSECTCLIPRECT
;
2061 emr
.emr
.nSize
= sizeof(emr
);
2062 emr
.rclClip
.left
= left
;
2063 emr
.rclClip
.top
= top
;
2064 emr
.rclClip
.right
= right
;
2065 emr
.rclClip
.bottom
= bottom
;
2066 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2069 BOOL
EMFDC_OffsetClipRgn( DC_ATTR
*dc_attr
, INT x
, INT y
)
2071 EMROFFSETCLIPRGN emr
;
2073 emr
.emr
.iType
= EMR_OFFSETCLIPRGN
;
2074 emr
.emr
.nSize
= sizeof(emr
);
2075 emr
.ptlOffset
.x
= x
;
2076 emr
.ptlOffset
.y
= y
;
2077 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2080 BOOL
EMFDC_ExtSelectClipRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, INT mode
)
2082 EMREXTSELECTCLIPRGN
*emr
;
2083 DWORD size
, rgnsize
;
2088 if (mode
!= RGN_COPY
) return ERROR
;
2091 else rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
2093 size
= rgnsize
+ offsetof(EMREXTSELECTCLIPRGN
,RgnData
);
2094 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
2095 if (rgnsize
) NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
2097 emr
->emr
.iType
= EMR_EXTSELECTCLIPRGN
;
2098 emr
->emr
.nSize
= size
;
2099 emr
->cbRgnData
= rgnsize
;
2102 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
2103 HeapFree( GetProcessHeap(), 0, emr
);
2107 BOOL
EMFDC_SetMapMode( DC_ATTR
*dc_attr
, INT mode
)
2111 emr
.emr
.iType
= EMR_SETMAPMODE
;
2112 emr
.emr
.nSize
= sizeof(emr
);
2114 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2117 BOOL
EMFDC_SetViewportExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2119 EMRSETVIEWPORTEXTEX emr
;
2121 emr
.emr
.iType
= EMR_SETVIEWPORTEXTEX
;
2122 emr
.emr
.nSize
= sizeof(emr
);
2123 emr
.szlExtent
.cx
= cx
;
2124 emr
.szlExtent
.cy
= cy
;
2125 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2128 BOOL
EMFDC_SetWindowExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2130 EMRSETWINDOWEXTEX emr
;
2132 emr
.emr
.iType
= EMR_SETWINDOWEXTEX
;
2133 emr
.emr
.nSize
= sizeof(emr
);
2134 emr
.szlExtent
.cx
= cx
;
2135 emr
.szlExtent
.cy
= cy
;
2136 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2139 BOOL
EMFDC_SetViewportOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2141 EMRSETVIEWPORTORGEX emr
;
2143 emr
.emr
.iType
= EMR_SETVIEWPORTORGEX
;
2144 emr
.emr
.nSize
= sizeof(emr
);
2145 emr
.ptlOrigin
.x
= x
;
2146 emr
.ptlOrigin
.y
= y
;
2147 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2150 BOOL
EMFDC_SetWindowOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2152 EMRSETWINDOWORGEX emr
;
2154 emr
.emr
.iType
= EMR_SETWINDOWORGEX
;
2155 emr
.emr
.nSize
= sizeof(emr
);
2156 emr
.ptlOrigin
.x
= x
;
2157 emr
.ptlOrigin
.y
= y
;
2158 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2161 BOOL
EMFDC_ScaleViewportExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2163 EMRSCALEVIEWPORTEXTEX emr
;
2165 emr
.emr
.iType
= EMR_SCALEVIEWPORTEXTEX
;
2166 emr
.emr
.nSize
= sizeof(emr
);
2168 emr
.xDenom
= x_denom
;
2170 emr
.yDenom
= y_denom
;
2171 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2174 BOOL
EMFDC_ScaleWindowExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2176 EMRSCALEWINDOWEXTEX emr
;
2178 emr
.emr
.iType
= EMR_SCALEWINDOWEXTEX
;
2179 emr
.emr
.nSize
= sizeof(emr
);
2181 emr
.xDenom
= x_denom
;
2183 emr
.yDenom
= y_denom
;
2184 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2187 BOOL
EMFDC_SetLayout( DC_ATTR
*dc_attr
, DWORD layout
)
2191 emr
.emr
.iType
= EMR_SETLAYOUT
;
2192 emr
.emr
.nSize
= sizeof(emr
);
2194 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2197 BOOL
EMFDC_SetWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
)
2199 EMRSETWORLDTRANSFORM emr
;
2201 emr
.emr
.iType
= EMR_SETWORLDTRANSFORM
;
2202 emr
.emr
.nSize
= sizeof(emr
);
2204 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2207 BOOL
EMFDC_ModifyWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
, DWORD mode
)
2209 EMRMODIFYWORLDTRANSFORM emr
;
2211 emr
.emr
.iType
= EMR_MODIFYWORLDTRANSFORM
;
2212 emr
.emr
.nSize
= sizeof(emr
);
2213 if (mode
== MWT_IDENTITY
)
2215 emr
.xform
.eM11
= 1.0f
;
2216 emr
.xform
.eM12
= 0.0f
;
2217 emr
.xform
.eM21
= 0.0f
;
2218 emr
.xform
.eM22
= 1.0f
;
2219 emr
.xform
.eDx
= 0.0f
;
2220 emr
.xform
.eDy
= 0.0f
;
2227 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2230 BOOL
EMFDC_SetMapperFlags( DC_ATTR
*dc_attr
, DWORD flags
)
2232 EMRSETMAPPERFLAGS emr
;
2234 emr
.emr
.iType
= EMR_SETMAPPERFLAGS
;
2235 emr
.emr
.nSize
= sizeof(emr
);
2236 emr
.dwFlags
= flags
;
2237 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2240 BOOL
EMFDC_AbortPath( DC_ATTR
*dc_attr
)
2242 struct emf
*emf
= dc_attr
->emf
;
2245 emr
.emr
.iType
= EMR_ABORTPATH
;
2246 emr
.emr
.nSize
= sizeof(emr
);
2249 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2252 BOOL
EMFDC_BeginPath( DC_ATTR
*dc_attr
)
2254 struct emf
*emf
= dc_attr
->emf
;
2257 emr
.emr
.iType
= EMR_BEGINPATH
;
2258 emr
.emr
.nSize
= sizeof(emr
);
2259 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
2265 BOOL
EMFDC_CloseFigure( DC_ATTR
*dc_attr
)
2269 emr
.emr
.iType
= EMR_CLOSEFIGURE
;
2270 emr
.emr
.nSize
= sizeof(emr
);
2271 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2274 BOOL
EMFDC_EndPath( DC_ATTR
*dc_attr
)
2276 struct emf
*emf
= dc_attr
->emf
;
2281 emr
.emr
.iType
= EMR_ENDPATH
;
2282 emr
.emr
.nSize
= sizeof(emr
);
2283 return emfdc_record( emf
, &emr
.emr
);
2286 BOOL
EMFDC_FlattenPath( DC_ATTR
*dc_attr
)
2290 emr
.emr
.iType
= EMR_FLATTENPATH
;
2291 emr
.emr
.nSize
= sizeof(emr
);
2292 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2295 BOOL
EMFDC_SelectClipPath( DC_ATTR
*dc_attr
, INT mode
)
2297 EMRSELECTCLIPPATH emr
;
2299 emr
.emr
.iType
= EMR_SELECTCLIPPATH
;
2300 emr
.emr
.nSize
= sizeof(emr
);
2302 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2305 BOOL
EMFDC_WidenPath( DC_ATTR
*dc_attr
)
2309 emr
.emr
.iType
= EMR_WIDENPATH
;
2310 emr
.emr
.nSize
= sizeof(emr
);
2311 return emfdc_record( dc_attr
->emf
, &emr
.emr
);
2314 void EMFDC_DeleteDC( DC_ATTR
*dc_attr
)
2316 struct emf
*emf
= dc_attr
->emf
;
2319 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2320 for (index
= 0; index
< emf
->handles_size
; index
++)
2321 if (emf
->handles
[index
])
2322 GDI_hdc_not_using_object( emf
->handles
[index
], emf
->dc_attr
->hdc
);
2323 HeapFree( GetProcessHeap(), 0, emf
->handles
);
2326 /*******************************************************************
2327 * GdiComment (GDI32.@)
2329 BOOL WINAPI
GdiComment( HDC hdc
, UINT bytes
, const BYTE
*buffer
)
2333 UINT total
, rounded_size
;
2336 if (!(dc_attr
= get_dc_attr( hdc
)) || !dc_attr
->emf
) return FALSE
;
2338 rounded_size
= (bytes
+3) & ~3;
2339 total
= offsetof(EMRGDICOMMENT
,Data
) + rounded_size
;
2341 emr
= HeapAlloc(GetProcessHeap(), 0, total
);
2342 emr
->emr
.iType
= EMR_GDICOMMENT
;
2343 emr
->emr
.nSize
= total
;
2344 emr
->cbData
= bytes
;
2345 memset(&emr
->Data
[bytes
], 0, rounded_size
- bytes
);
2346 memcpy(&emr
->Data
[0], buffer
, bytes
);
2348 ret
= emfdc_record( dc_attr
->emf
, &emr
->emr
);
2350 HeapFree(GetProcessHeap(), 0, emr
);
2355 /**********************************************************************
2356 * CreateEnhMetaFileA (GDI32.@)
2358 HDC WINAPI
CreateEnhMetaFileA( HDC hdc
, const char *filename
, const RECT
*rect
,
2359 const char *description
)
2361 WCHAR
*filenameW
= NULL
;
2362 WCHAR
*descriptionW
= NULL
;
2363 DWORD len1
, len2
, total
;
2368 total
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
2369 filenameW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2370 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, total
);
2375 len1
= strlen(description
);
2376 len2
= strlen(description
+ len1
+ 1);
2377 total
= MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, NULL
, 0 );
2378 descriptionW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2379 MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, descriptionW
, total
);
2382 ret
= CreateEnhMetaFileW( hdc
, filenameW
, rect
, descriptionW
);
2384 HeapFree( GetProcessHeap(), 0, filenameW
);
2385 HeapFree( GetProcessHeap(), 0, descriptionW
);
2389 /**********************************************************************
2390 * CreateEnhMetaFileW (GDI32.@)
2392 HDC WINAPI
CreateEnhMetaFileW( HDC hdc
, const WCHAR
*filename
, const RECT
*rect
,
2393 const WCHAR
*description
)
2399 DWORD size
= 0, length
= 0;
2401 TRACE( "(%p %s %s %s)\n", hdc
, debugstr_w(filename
), wine_dbgstr_rect(rect
),
2402 debugstr_w(description
) );
2404 if (!(ret
= NtGdiCreateMetafileDC( hdc
))) return 0;
2406 if (!(dc_attr
= get_dc_attr( ret
)) || !(emf
= HeapAlloc( GetProcessHeap(), 0, sizeof(*emf
) )))
2412 emf
->dc_attr
= dc_attr
;
2415 if (description
) /* App name\0Title\0\0 */
2417 length
= lstrlenW( description
);
2418 length
+= lstrlenW( description
+ length
+ 1 );
2422 size
= sizeof(ENHMETAHEADER
) + (length
+ 3) / 4 * 4;
2424 if (!(emf
->emh
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
)))
2429 emf
->dc_attr
= dc_attr
;
2431 emf
->handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
2432 HANDLE_LIST_INC
* sizeof(emf
->handles
[0]) );
2433 emf
->handles_size
= HANDLE_LIST_INC
;
2434 emf
->cur_handles
= 1;
2440 emf
->emh
->iType
= EMR_HEADER
;
2441 emf
->emh
->nSize
= size
;
2443 dc_attr
->emf_bounds
.left
= dc_attr
->emf_bounds
.top
= 0;
2444 dc_attr
->emf_bounds
.right
= dc_attr
->emf_bounds
.bottom
= -1;
2448 emf
->emh
->rclFrame
.left
= rect
->left
;
2449 emf
->emh
->rclFrame
.top
= rect
->top
;
2450 emf
->emh
->rclFrame
.right
= rect
->right
;
2451 emf
->emh
->rclFrame
.bottom
= rect
->bottom
;
2455 /* Set this to {0,0 - -1,-1} and update it at the end */
2456 emf
->emh
->rclFrame
.left
= emf
->emh
->rclFrame
.top
= 0;
2457 emf
->emh
->rclFrame
.right
= emf
->emh
->rclFrame
.bottom
= -1;
2460 emf
->emh
->dSignature
= ENHMETA_SIGNATURE
;
2461 emf
->emh
->nVersion
= 0x10000;
2462 emf
->emh
->nBytes
= emf
->emh
->nSize
;
2463 emf
->emh
->nRecords
= 1;
2464 emf
->emh
->nHandles
= 1;
2466 emf
->emh
->sReserved
= 0; /* According to docs, this is reserved and must be 0 */
2467 emf
->emh
->nDescription
= length
/ 2;
2469 emf
->emh
->offDescription
= length
? sizeof(ENHMETAHEADER
) : 0;
2471 emf
->emh
->nPalEntries
= 0; /* I guess this should start at 0 */
2473 /* Size in pixels */
2474 emf
->emh
->szlDevice
.cx
= GetDeviceCaps( ret
, HORZRES
);
2475 emf
->emh
->szlDevice
.cy
= GetDeviceCaps( ret
, VERTRES
);
2477 /* Size in millimeters */
2478 emf
->emh
->szlMillimeters
.cx
= GetDeviceCaps( ret
, HORZSIZE
);
2479 emf
->emh
->szlMillimeters
.cy
= GetDeviceCaps( ret
, VERTSIZE
);
2481 /* Size in micrometers */
2482 emf
->emh
->szlMicrometers
.cx
= emf
->emh
->szlMillimeters
.cx
* 1000;
2483 emf
->emh
->szlMicrometers
.cy
= emf
->emh
->szlMillimeters
.cy
* 1000;
2485 memcpy( (char *)emf
->emh
+ sizeof(ENHMETAHEADER
), description
, length
);
2487 if (filename
) /* disk based metafile */
2489 if ((file
= CreateFileW( filename
, GENERIC_WRITE
| GENERIC_READ
, 0,
2490 NULL
, CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
)
2498 TRACE( "returning %p\n", ret
);
2502 /******************************************************************
2503 * CloseEnhMetaFile (GDI32.@)
2505 HENHMETAFILE WINAPI
CloseEnhMetaFile( HDC hdc
)
2513 TRACE("(%p)\n", hdc
);
2515 if (!(dc_attr
= get_dc_attr( hdc
)) || !dc_attr
->emf
) return 0;
2518 if (dc_attr
->save_level
)
2519 RestoreDC( hdc
, 1 );
2521 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2522 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2524 emr
.emr
.iType
= EMR_EOF
;
2525 emr
.emr
.nSize
= sizeof(emr
);
2526 emr
.nPalEntries
= 0;
2527 emr
.offPalEntries
= FIELD_OFFSET(EMREOF
, nSizeLast
);
2528 emr
.nSizeLast
= emr
.emr
.nSize
;
2529 emfdc_record( emf
, &emr
.emr
);
2531 emf
->emh
->rclBounds
= dc_attr
->emf_bounds
;
2533 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2534 if (emf
->emh
->rclFrame
.left
> emf
->emh
->rclFrame
.right
)
2536 emf
->emh
->rclFrame
.left
= emf
->emh
->rclBounds
.left
*
2537 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2538 emf
->emh
->rclFrame
.top
= emf
->emh
->rclBounds
.top
*
2539 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2540 emf
->emh
->rclFrame
.right
= emf
->emh
->rclBounds
.right
*
2541 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2542 emf
->emh
->rclFrame
.bottom
= emf
->emh
->rclBounds
.bottom
*
2543 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2546 if (emf
->file
) /* disk based metafile */
2548 if (!WriteFile( emf
->file
, emf
->emh
, emf
->emh
->nBytes
, NULL
, NULL
))
2550 CloseHandle( emf
->file
);
2553 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2554 mapping
= CreateFileMappingA( emf
->file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
2555 TRACE( "mapping = %p\n", mapping
);
2556 emf
->emh
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
2557 TRACE( "view = %p\n", emf
->emh
);
2558 CloseHandle( mapping
);
2559 CloseHandle( emf
->file
);
2562 hmf
= EMF_Create_HENHMETAFILE( emf
->emh
, emf
->emh
->nBytes
, emf
->file
!= 0 );
2563 emf
->emh
= NULL
; /* So it won't be deleted */