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 PALETTEENTRY
*palette
;
49 #define HANDLE_LIST_INC 20
50 static const RECTL empty_bounds
= { 0, 0, -1, -1 };
52 static struct emf
*get_dc_emf( DC_ATTR
*dc_attr
)
54 return (struct emf
*)(UINT_PTR
)dc_attr
->emf
;
57 static HDC
dc_attr_handle( DC_ATTR
*dc_attr
)
59 return UlongToHandle( dc_attr
->hdc
);
62 static BOOL
emfdc_record( struct emf
*emf
, EMR
*emr
)
67 TRACE( "record %ld, size %ld\n", emr
->iType
, emr
->nSize
);
69 assert( !(emr
->nSize
& 3) );
71 emf
->emh
->nBytes
+= emr
->nSize
;
74 size
= HeapSize( GetProcessHeap(), 0, emf
->emh
);
75 len
= emf
->emh
->nBytes
;
78 size
+= (size
/ 2) + emr
->nSize
;
79 emh
= HeapReAlloc( GetProcessHeap(), 0, emf
->emh
, size
);
80 if (!emh
) return FALSE
;
83 memcpy( (char *)emf
->emh
+ emf
->emh
->nBytes
- emr
->nSize
, emr
, emr
->nSize
);
87 static void emfdc_update_bounds( struct emf
*emf
, RECTL
*rect
)
89 RECTL
*bounds
= &emf
->dc_attr
->emf_bounds
;
90 RECTL vport_rect
= *rect
;
92 LPtoDP( dc_attr_handle( emf
->dc_attr
), (POINT
*)&vport_rect
, 2 );
94 /* The coordinate systems may be mirrored
95 (LPtoDP handles points, not rectangles) */
96 if (vport_rect
.left
> vport_rect
.right
)
98 LONG temp
= vport_rect
.right
;
99 vport_rect
.right
= vport_rect
.left
;
100 vport_rect
.left
= temp
;
102 if (vport_rect
.top
> vport_rect
.bottom
)
104 LONG temp
= vport_rect
.bottom
;
105 vport_rect
.bottom
= vport_rect
.top
;
106 vport_rect
.top
= temp
;
109 if (bounds
->left
> bounds
->right
)
111 /* first bounding rectangle */
112 *bounds
= vport_rect
;
116 bounds
->left
= min(bounds
->left
, vport_rect
.left
);
117 bounds
->top
= min(bounds
->top
, vport_rect
.top
);
118 bounds
->right
= max(bounds
->right
, vport_rect
.right
);
119 bounds
->bottom
= max(bounds
->bottom
, vport_rect
.bottom
);
123 static UINT
get_bitmap_info( HDC
*hdc
, HBITMAP
*bitmap
, BITMAPINFO
*info
)
130 if (!(info_size
= GetObjectW( *bitmap
, sizeof(dib
), &dib
))) return 0;
132 if (info_size
== sizeof(dib
))
135 blit_bitmap
= *bitmap
;
139 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
140 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
141 BITMAP bmp
= dib
.dsBm
;
145 assert( info_size
== sizeof(BITMAP
) );
147 dib_info
->bmiHeader
.biSize
= sizeof(dib_info
->bmiHeader
);
148 dib_info
->bmiHeader
.biWidth
= bmp
.bmWidth
;
149 dib_info
->bmiHeader
.biHeight
= bmp
.bmHeight
;
150 dib_info
->bmiHeader
.biPlanes
= 1;
151 dib_info
->bmiHeader
.biBitCount
= bmp
.bmBitsPixel
;
152 dib_info
->bmiHeader
.biCompression
= BI_RGB
;
153 dib_info
->bmiHeader
.biSizeImage
= 0;
154 dib_info
->bmiHeader
.biXPelsPerMeter
= 0;
155 dib_info
->bmiHeader
.biYPelsPerMeter
= 0;
156 dib_info
->bmiHeader
.biClrUsed
= 0;
157 dib_info
->bmiHeader
.biClrImportant
= 0;
158 switch (dib_info
->bmiHeader
.biBitCount
)
161 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
162 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
163 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
166 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
167 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
168 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
171 if (dib_info
->bmiHeader
.biBitCount
> 8) break;
172 if (!(palette
= GetCurrentObject( *hdc
, OBJ_PAL
))) return FALSE
;
173 if (!GetPaletteEntries( palette
, 0, 256, (PALETTEENTRY
*)dib_info
->bmiColors
))
177 if (!(blit_dc
= NtGdiCreateCompatibleDC( *hdc
))) return FALSE
;
178 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
180 if (!SelectObject( blit_dc
, blit_bitmap
)) goto err
;
181 if (!BitBlt( blit_dc
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, *hdc
, 0, 0, SRCCOPY
))
184 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, info
, DIB_RGB_COLORS
))
187 bpp
= info
->bmiHeader
.biBitCount
;
189 return sizeof(BITMAPINFOHEADER
) + (1 << bpp
) * sizeof(RGBQUAD
);
190 else if (bpp
== 16 || bpp
== 32)
191 return sizeof(BITMAPINFOHEADER
) + 3 * sizeof(RGBQUAD
);
193 return sizeof(BITMAPINFOHEADER
);
196 if (blit_dc
&& blit_dc
!= *hdc
) DeleteDC( blit_dc
);
197 if (blit_bitmap
&& blit_bitmap
!= *bitmap
) DeleteObject( blit_bitmap
);
201 /*******************************************************************************************
202 * Verify that the DIB parameters are valid.
204 static BOOL
is_valid_dib_format( const BITMAPINFOHEADER
*info
, BOOL allow_compression
)
206 if (info
->biWidth
<= 0) return FALSE
;
207 if (info
->biHeight
== 0) return FALSE
;
209 if (allow_compression
&& (info
->biCompression
== BI_RLE4
|| info
->biCompression
== BI_RLE8
))
211 if (info
->biHeight
< 0) return FALSE
;
212 if (!info
->biSizeImage
) return FALSE
;
213 return info
->biBitCount
== (info
->biCompression
== BI_RLE4
? 4 : 8);
216 if (!info
->biPlanes
) return FALSE
;
218 /* check for size overflow */
219 if (!info
->biBitCount
) return FALSE
;
220 if (UINT_MAX
/ info
->biBitCount
< info
->biWidth
) return FALSE
;
221 if (UINT_MAX
/ get_dib_stride( info
->biWidth
, info
->biBitCount
) < abs( info
->biHeight
)) return FALSE
;
223 switch (info
->biBitCount
)
229 return (info
->biCompression
== BI_RGB
);
232 return (info
->biCompression
== BI_BITFIELDS
|| info
->biCompression
== BI_RGB
);
238 static BOOL
emf_parse_user_bitmapinfo( BITMAPINFOHEADER
*dst
, const BITMAPINFOHEADER
*info
,
239 UINT coloruse
, BOOL allow_compression
,
240 UINT
*bmi_size
, UINT
*img_size
)
242 UINT colour_table_size
;
244 if (coloruse
> DIB_PAL_COLORS
+ 1) return FALSE
; /* FIXME: handle DIB_PAL_COLORS+1 format */
245 if (!info
) return FALSE
;
247 memset(dst
, 0, sizeof(*dst
));
249 if (info
->biSize
== sizeof(BITMAPCOREHEADER
))
251 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
252 dst
->biWidth
= core
->bcWidth
;
253 dst
->biHeight
= core
->bcHeight
;
254 dst
->biPlanes
= core
->bcPlanes
;
255 dst
->biBitCount
= core
->bcBitCount
;
256 dst
->biCompression
= BI_RGB
;
257 dst
->biXPelsPerMeter
= 0;
258 dst
->biYPelsPerMeter
= 0;
260 dst
->biClrImportant
= 0;
262 else if (info
->biSize
>= sizeof(BITMAPINFOHEADER
)) /* assume BITMAPINFOHEADER */
268 WARN( "(%lu): unknown/wrong size for header\n", info
->biSize
);
272 dst
->biSize
= sizeof(*dst
);
274 if (!is_valid_dib_format( dst
, allow_compression
)) return FALSE
;
276 colour_table_size
= 0;
277 if (dst
->biCompression
== BI_BITFIELDS
)
279 colour_table_size
= 3 * sizeof(DWORD
);
281 else if (dst
->biBitCount
<= 8)
283 UINT elm_size
= coloruse
== DIB_PAL_COLORS
? sizeof(WORD
) : sizeof(DWORD
);
284 UINT colours
= dst
->biClrUsed
;
286 /* Windows never truncates colour tables, even if they are
287 * unnecessarily big (> 1<<bpp). We emulate this behaviour. */
289 if (colours
> UINT_MAX
/ elm_size
)
291 WARN( "too many colours in palette (%u > %u)\n",
292 colours
, UINT_MAX
/ elm_size
);
296 colour_table_size
= colours
* elm_size
;
299 *bmi_size
= sizeof(BITMAPINFOHEADER
) + colour_table_size
;
300 if (*bmi_size
< sizeof(BITMAPINFOHEADER
))
303 if (dst
->biCompression
== BI_RGB
|| dst
->biCompression
== BI_BITFIELDS
)
304 *img_size
= get_dib_stride( dst
->biWidth
, dst
->biBitCount
) * abs( dst
->biHeight
);
306 *img_size
= dst
->biSizeImage
;
311 static void emf_copy_colours_from_user_bitmapinfo( BITMAPINFO
*dst
, const BITMAPINFO
*info
, UINT coloruse
)
313 if (dst
->bmiHeader
.biCompression
== BI_BITFIELDS
)
315 /* bitfields are always at bmiColors even in larger structures */
316 memcpy( dst
->bmiColors
, info
->bmiColors
, 3 * sizeof(DWORD
) );
318 else if (dst
->bmiHeader
.biBitCount
<= 8)
320 void *src_colors
= (char *)info
+ info
->bmiHeader
.biSize
;
321 unsigned int colors
= dst
->bmiHeader
.biClrUsed
;
323 if (!colors
) colors
= 1 << dst
->bmiHeader
.biBitCount
;
325 if (coloruse
== DIB_PAL_COLORS
)
327 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(WORD
) );
329 else if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
331 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(RGBQUAD
) );
336 RGBTRIPLE
*triple
= (RGBTRIPLE
*)src_colors
;
337 for (i
= 0; i
< colors
; i
++)
339 dst
->bmiColors
[i
].rgbRed
= triple
[i
].rgbtRed
;
340 dst
->bmiColors
[i
].rgbGreen
= triple
[i
].rgbtGreen
;
341 dst
->bmiColors
[i
].rgbBlue
= triple
[i
].rgbtBlue
;
342 dst
->bmiColors
[i
].rgbReserved
= 0;
348 static UINT
emfdc_add_handle( struct emf
*emf
, HGDIOBJ obj
)
352 for (index
= 0; index
< emf
->handles_size
; index
++)
353 if (emf
->handles
[index
] == 0) break;
355 if (index
== emf
->handles_size
)
357 emf
->handles_size
+= HANDLE_LIST_INC
;
358 emf
->handles
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
360 emf
->handles_size
* sizeof(emf
->handles
[0]) );
362 emf
->handles
[index
] = obj
;
365 if (emf
->cur_handles
> emf
->emh
->nHandles
)
366 emf
->emh
->nHandles
++;
368 return index
+ 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
371 static UINT
emfdc_find_object( struct emf
*emf
, HGDIOBJ obj
)
375 for (index
= 0; index
< emf
->handles_size
; index
++)
376 if (emf
->handles
[index
] == obj
) return index
+ 1;
381 static void emfdc_delete_object( HDC hdc
, HGDIOBJ obj
)
383 DC_ATTR
*dc_attr
= get_dc_attr( hdc
);
384 struct emf
*emf
= get_dc_emf( dc_attr
);
388 if(!(index
= emfdc_find_object( emf
, obj
))) return;
390 emr
.emr
.iType
= EMR_DELETEOBJECT
;
391 emr
.emr
.nSize
= sizeof(emr
);
392 emr
.ihObject
= index
;
394 emfdc_record( emf
, &emr
.emr
);
396 emf
->handles
[index
- 1] = 0;
400 static BOOL
emfdc_add_palette_entry( struct emf
*emf
, PALETTEENTRY
*entry
)
404 for (i
= 0; i
< emf
->palette_used
; i
++)
406 if (emf
->palette
[i
].peRed
== entry
->peRed
&&
407 emf
->palette
[i
].peGreen
== entry
->peGreen
&&
408 emf
->palette
[i
].peBlue
== entry
->peBlue
) return TRUE
;
411 if (emf
->palette_size
== emf
->palette_used
)
413 if (!emf
->palette_size
)
415 emf
->palette
= HeapAlloc( GetProcessHeap(), 0,
416 8 * sizeof(*emf
->palette
) );
417 if (!emf
->palette
) return FALSE
;
418 emf
->palette_size
= 8;
422 void *new_palette
= HeapReAlloc( GetProcessHeap(), 0, emf
->palette
,
423 2 * emf
->palette_size
* sizeof(*emf
->palette
) );
424 if (!new_palette
) return FALSE
;
425 emf
->palette
= new_palette
;
426 emf
->palette_size
*= 2;
430 emf
->palette
[emf
->palette_used
++] = *entry
;
434 static DWORD
emfdc_create_brush( struct emf
*emf
, HBRUSH brush
)
439 if (!GetObjectA( brush
, sizeof(logbrush
), &logbrush
)) return 0;
441 switch (logbrush
.lbStyle
) {
446 EMRCREATEBRUSHINDIRECT emr
;
447 emr
.emr
.iType
= EMR_CREATEBRUSHINDIRECT
;
448 emr
.emr
.nSize
= sizeof(emr
);
449 emr
.ihBrush
= index
= emfdc_add_handle( emf
, brush
);
450 emr
.lb
.lbStyle
= logbrush
.lbStyle
;
451 emr
.lb
.lbColor
= logbrush
.lbColor
;
452 emr
.lb
.lbHatch
= logbrush
.lbHatch
;
454 if(!emfdc_record( emf
, &emr
.emr
))
461 EMRCREATEDIBPATTERNBRUSHPT
*emr
;
462 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
463 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
467 if (!__wine_get_brush_bitmap_info( brush
, info
, NULL
, &usage
)) break;
468 info_size
= get_dib_info_size( info
, usage
);
470 emr
= HeapAlloc( GetProcessHeap(), 0,
471 sizeof(EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
) +
472 info_size
+info
->bmiHeader
.biSizeImage
);
475 /* FIXME: There is an extra DWORD written by native before the BMI.
476 * Not sure what it's meant to contain.
478 emr
->offBmi
= sizeof( EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
);
479 *(DWORD
*)(emr
+ 1) = 0x20000000;
481 if (logbrush
.lbStyle
== BS_PATTERN
&& info
->bmiHeader
.biBitCount
== 1)
483 /* Presumably to reduce the size of the written EMF, MS supports an
484 * undocumented iUsage value of 2, indicating a mono bitmap without the
485 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
486 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
487 * irrelevant/constant for monochrome bitmaps.
488 * FIXME: It may be that the DIB functions themselves accept this value.
490 emr
->emr
.iType
= EMR_CREATEMONOBRUSH
;
491 usage
= DIB_PAL_INDICES
;
492 emr
->cbBmi
= sizeof( BITMAPINFOHEADER
);
496 emr
->emr
.iType
= EMR_CREATEDIBPATTERNBRUSHPT
;
497 emr
->cbBmi
= info_size
;
499 emr
->ihBrush
= index
= emfdc_add_handle( emf
, brush
);
501 emr
->offBits
= emr
->offBmi
+ emr
->cbBmi
;
502 emr
->cbBits
= info
->bmiHeader
.biSizeImage
;
503 emr
->emr
.nSize
= emr
->offBits
+ emr
->cbBits
;
505 if (info
->bmiHeader
.biClrUsed
== 1 << info
->bmiHeader
.biBitCount
)
506 info
->bmiHeader
.biClrUsed
= 0;
507 memcpy( (BYTE
*)emr
+ emr
->offBmi
, info
, emr
->cbBmi
);
508 __wine_get_brush_bitmap_info( brush
, NULL
, (char *)emr
+ emr
->offBits
, NULL
);
510 if (!emfdc_record( emf
, &emr
->emr
)) index
= 0;
511 HeapFree( GetProcessHeap(), 0, emr
);
516 FIXME("Unknown style %x\n", logbrush
.lbStyle
);
523 static BOOL
emfdc_select_brush( DC_ATTR
*dc_attr
, HBRUSH brush
)
525 struct emf
*emf
= get_dc_emf( dc_attr
);
530 /* If the object is a stock brush object, do not need to create it.
531 * See definitions in wingdi.h for range of stock brushes.
532 * We do however have to handle setting the higher order bit to
533 * designate that this is a stock object.
535 for (i
= WHITE_BRUSH
; i
<= DC_BRUSH
; i
++)
537 if (brush
== GetStockObject(i
))
539 index
= i
| 0x80000000;
544 if (!index
&& !(index
= emfdc_find_object( emf
, brush
)))
546 if (!(index
= emfdc_create_brush( emf
, brush
))) return 0;
547 GDI_hdc_using_object( brush
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
550 emr
.emr
.iType
= EMR_SELECTOBJECT
;
551 emr
.emr
.nSize
= sizeof(emr
);
552 emr
.ihObject
= index
;
553 return emfdc_record( emf
, &emr
.emr
);
556 static BOOL
emfdc_create_font( struct emf
*emf
, HFONT font
)
559 EMREXTCREATEFONTINDIRECTW emr
;
562 if (!GetObjectW( font
, sizeof(emr
.elfw
.elfLogFont
), &emr
.elfw
.elfLogFont
)) return FALSE
;
564 emr
.emr
.iType
= EMR_EXTCREATEFONTINDIRECTW
;
565 emr
.emr
.nSize
= (sizeof(emr
) + 3) / 4 * 4;
566 emr
.ihFont
= index
= emfdc_add_handle( emf
, font
);
567 emr
.elfw
.elfFullName
[0] = '\0';
568 emr
.elfw
.elfStyle
[0] = '\0';
569 emr
.elfw
.elfVersion
= 0;
570 emr
.elfw
.elfStyleSize
= 0;
571 emr
.elfw
.elfMatch
= 0;
572 emr
.elfw
.elfReserved
= 0;
573 for (i
= 0; i
< ELF_VENDOR_SIZE
; i
++)
574 emr
.elfw
.elfVendorId
[i
] = 0;
575 emr
.elfw
.elfCulture
= PAN_CULTURE_LATIN
;
576 emr
.elfw
.elfPanose
.bFamilyType
= PAN_NO_FIT
;
577 emr
.elfw
.elfPanose
.bSerifStyle
= PAN_NO_FIT
;
578 emr
.elfw
.elfPanose
.bWeight
= PAN_NO_FIT
;
579 emr
.elfw
.elfPanose
.bProportion
= PAN_NO_FIT
;
580 emr
.elfw
.elfPanose
.bContrast
= PAN_NO_FIT
;
581 emr
.elfw
.elfPanose
.bStrokeVariation
= PAN_NO_FIT
;
582 emr
.elfw
.elfPanose
.bArmStyle
= PAN_NO_FIT
;
583 emr
.elfw
.elfPanose
.bLetterform
= PAN_NO_FIT
;
584 emr
.elfw
.elfPanose
.bMidline
= PAN_NO_FIT
;
585 emr
.elfw
.elfPanose
.bXHeight
= PAN_NO_FIT
;
587 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
590 static BOOL
emfdc_select_font( DC_ATTR
*dc_attr
, HFONT font
)
592 struct emf
*emf
= get_dc_emf( dc_attr
);
597 /* If the object is a stock font object, do not need to create it.
598 * See definitions in wingdi.h for range of stock fonts.
599 * We do however have to handle setting the higher order bit to
600 * designate that this is a stock object.
603 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
605 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
))
607 index
= i
| 0x80000000;
612 if (!(index
= emfdc_find_object( emf
, font
)))
614 if (!(index
= emfdc_create_font( emf
, font
))) return FALSE
;
615 GDI_hdc_using_object( font
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
619 emr
.emr
.iType
= EMR_SELECTOBJECT
;
620 emr
.emr
.nSize
= sizeof(emr
);
621 emr
.ihObject
= index
;
622 return emfdc_record( emf
, &emr
.emr
);
625 static DWORD
emfdc_create_pen( struct emf
*emf
, HPEN hPen
)
630 if (!GetObjectW( hPen
, sizeof(emr
.lopn
), &emr
.lopn
))
632 /* must be an extended pen */
634 INT size
= GetObjectW( hPen
, 0, NULL
);
638 elp
= HeapAlloc( GetProcessHeap(), 0, size
);
640 GetObjectW( hPen
, size
, elp
);
641 /* FIXME: add support for user style pens */
642 emr
.lopn
.lopnStyle
= elp
->elpPenStyle
;
643 emr
.lopn
.lopnWidth
.x
= elp
->elpWidth
;
644 emr
.lopn
.lopnWidth
.y
= 0;
645 emr
.lopn
.lopnColor
= elp
->elpColor
;
647 HeapFree( GetProcessHeap(), 0, elp
);
650 emr
.emr
.iType
= EMR_CREATEPEN
;
651 emr
.emr
.nSize
= sizeof(emr
);
652 emr
.ihPen
= index
= emfdc_add_handle( emf
, hPen
);
653 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
656 static BOOL
emfdc_select_pen( DC_ATTR
*dc_attr
, HPEN pen
)
658 struct emf
*emf
= get_dc_emf( dc_attr
);
663 /* If the object is a stock pen object, do not need to create it.
664 * See definitions in wingdi.h for range of stock pens.
665 * We do however have to handle setting the higher order bit to
666 * designate that this is a stock object.
669 for (i
= WHITE_PEN
; i
<= DC_PEN
; i
++)
671 if (pen
== GetStockObject(i
))
673 index
= i
| 0x80000000;
677 if (!index
&& !(index
= emfdc_find_object( emf
, pen
)))
679 if (!(index
= emfdc_create_pen( emf
, pen
))) return FALSE
;
680 GDI_hdc_using_object( pen
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
683 emr
.emr
.iType
= EMR_SELECTOBJECT
;
684 emr
.emr
.nSize
= sizeof(emr
);
685 emr
.ihObject
= index
;
686 return emfdc_record( emf
, &emr
.emr
);
689 static DWORD
emfdc_create_palette( struct emf
*emf
, HPALETTE hPal
)
691 BYTE data
[offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[256] )];
692 EMRCREATEPALETTE
*hdr
= (EMRCREATEPALETTE
*)data
;
695 memset( data
, 0, sizeof(data
) );
697 hdr
->lgpl
.palVersion
= 0x300;
698 hdr
->lgpl
.palNumEntries
= GetPaletteEntries( hPal
, 0, 256, hdr
->lgpl
.palPalEntry
);
699 if (!hdr
->lgpl
.palNumEntries
)
702 for (i
= 0; i
< hdr
->lgpl
.palNumEntries
; i
++)
704 hdr
->lgpl
.palPalEntry
[i
].peFlags
= 0;
705 emfdc_add_palette_entry( emf
, hdr
->lgpl
.palPalEntry
+ i
);
708 hdr
->emr
.iType
= EMR_CREATEPALETTE
;
709 hdr
->emr
.nSize
= offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[hdr
->lgpl
.palNumEntries
] );
710 hdr
->ihPal
= emfdc_add_handle( emf
, hPal
);
712 if (!emfdc_record( emf
, &hdr
->emr
))
717 BOOL
EMFDC_SelectPalette( DC_ATTR
*dc_attr
, HPALETTE palette
)
719 struct emf
*emf
= get_dc_emf( dc_attr
);
720 EMRSELECTPALETTE emr
;
723 if (palette
== GetStockObject( DEFAULT_PALETTE
))
725 index
= DEFAULT_PALETTE
| 0x80000000;
727 else if (!(index
= emfdc_find_object( emf
, palette
)))
729 if (!(index
= emfdc_create_palette( emf
, palette
))) return 0;
730 GDI_hdc_using_object( palette
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
733 emr
.emr
.iType
= EMR_SELECTPALETTE
;
734 emr
.emr
.nSize
= sizeof(emr
);
736 return emfdc_record( emf
, &emr
.emr
);
739 BOOL
EMFDC_RealizePalette( DC_ATTR
*dc_attr
)
741 HPALETTE palette
= GetCurrentObject( dc_attr_handle( dc_attr
), OBJ_PAL
);
742 struct emf
*emf
= get_dc_emf( dc_attr
);
743 EMRREALIZEPALETTE emr
;
745 if (palette
== GetStockObject( DEFAULT_PALETTE
))
748 emr
.emr
.iType
= EMR_REALIZEPALETTE
;
749 emr
.emr
.nSize
= sizeof(emr
);
750 return emfdc_record( emf
, &emr
.emr
);
753 BOOL
EMFDC_SelectObject( DC_ATTR
*dc_attr
, HGDIOBJ obj
)
755 switch (gdi_handle_type( obj
))
757 case NTGDI_OBJ_BRUSH
:
758 return emfdc_select_brush( dc_attr
, obj
);
760 return emfdc_select_font( dc_attr
, obj
);
762 case NTGDI_OBJ_EXTPEN
:
763 return emfdc_select_pen( dc_attr
, obj
);
769 /* determine if we can use 16-bit points to store all the input points */
770 static BOOL
can_use_short_points( const POINT
*pts
, UINT count
)
774 for (i
= 0; i
< count
; i
++)
775 if (((pts
[i
].x
+ 0x8000) & ~0xffff) || ((pts
[i
].y
+ 0x8000) & ~0xffff))
780 /* store points in either long or short format; return a pointer to the end of the stored data */
781 static void *store_points( POINTL
*dest
, const POINT
*pts
, UINT count
, BOOL short_points
)
786 POINTS
*dest_short
= (POINTS
*)dest
;
788 for (i
= 0; i
< count
; i
++)
790 dest_short
[i
].x
= pts
[i
].x
;
791 dest_short
[i
].y
= pts
[i
].y
;
793 return dest_short
+ count
;
797 memcpy( dest
, pts
, count
* sizeof(*dest
) );
802 /* compute the bounds of an array of points, optionally including the current position */
803 static void get_points_bounds( RECTL
*bounds
, const POINT
*pts
, UINT count
, DC_ATTR
*dc_attr
)
809 bounds
->left
= bounds
->right
= dc_attr
->cur_pos
.x
;
810 bounds
->top
= bounds
->bottom
= dc_attr
->cur_pos
.y
;
814 bounds
->left
= bounds
->right
= pts
[0].x
;
815 bounds
->top
= bounds
->bottom
= pts
[0].y
;
817 else *bounds
= empty_bounds
;
819 for (i
= 0; i
< count
; i
++)
821 bounds
->left
= min( bounds
->left
, pts
[i
].x
);
822 bounds
->right
= max( bounds
->right
, pts
[i
].x
);
823 bounds
->top
= min( bounds
->top
, pts
[i
].y
);
824 bounds
->bottom
= max( bounds
->bottom
, pts
[i
].y
);
828 /* helper for path stroke and fill functions */
829 static BOOL
emfdrv_stroke_and_fill_path( struct emf
*emf
, INT type
)
831 EMRSTROKEANDFILLPATH emr
;
834 emr
.emr
.iType
= type
;
835 emr
.emr
.nSize
= sizeof(emr
);
836 emr
.rclBounds
= empty_bounds
;
838 if ((region
= NtGdiPathToRegion( dc_attr_handle( emf
->dc_attr
))))
840 NtGdiGetRgnBox( region
, (RECT
*)&emr
.rclBounds
);
841 DeleteObject( region
);
844 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
845 if (!region
) return FALSE
;
846 emfdc_update_bounds( emf
, &emr
.rclBounds
);
850 BOOL
EMFDC_MoveTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
852 struct emf
*emf
= get_dc_emf( dc_attr
);
855 emr
.emr
.iType
= EMR_MOVETOEX
;
856 emr
.emr
.nSize
= sizeof(emr
);
859 return emfdc_record( emf
, &emr
.emr
);
862 BOOL
EMFDC_LineTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
866 emr
.emr
.iType
= EMR_LINETO
;
867 emr
.emr
.nSize
= sizeof(emr
);
870 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
873 BOOL
EMFDC_ArcChordPie( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
,
874 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD type
)
876 struct emf
*emf
= get_dc_emf( dc_attr
);
880 if (left
== right
|| top
== bottom
) return FALSE
;
882 if (left
> right
) { temp
= left
; left
= right
; right
= temp
; }
883 if (top
> bottom
) { temp
= top
; top
= bottom
; bottom
= temp
; }
885 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
891 emr
.emr
.iType
= type
;
892 emr
.emr
.nSize
= sizeof(emr
);
893 emr
.rclBox
.left
= left
;
894 emr
.rclBox
.top
= top
;
895 emr
.rclBox
.right
= right
;
896 emr
.rclBox
.bottom
= bottom
;
897 emr
.ptlStart
.x
= xstart
;
898 emr
.ptlStart
.y
= ystart
;
901 return emfdc_record( emf
, &emr
.emr
);
904 BOOL
EMFDC_AngleArc( DC_ATTR
*dc_attr
, INT x
, INT y
, DWORD radius
, FLOAT start
, FLOAT sweep
)
908 emr
.emr
.iType
= EMR_ANGLEARC
;
909 emr
.emr
.nSize
= sizeof( emr
);
912 emr
.nRadius
= radius
;
913 emr
.eStartAngle
= start
;
914 emr
.eSweepAngle
= sweep
;
915 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
918 BOOL
EMFDC_Ellipse( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
920 struct emf
*emf
= get_dc_emf( dc_attr
);
923 if (left
== right
|| top
== bottom
) return FALSE
;
925 emr
.emr
.iType
= EMR_ELLIPSE
;
926 emr
.emr
.nSize
= sizeof(emr
);
927 emr
.rclBox
.left
= min( left
, right
);
928 emr
.rclBox
.top
= min( top
, bottom
);
929 emr
.rclBox
.right
= max( left
, right
);
930 emr
.rclBox
.bottom
= max( top
, bottom
);
931 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
936 return emfdc_record( emf
, &emr
.emr
);
939 BOOL
EMFDC_Rectangle( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
941 struct emf
*emf
= get_dc_emf( dc_attr
);
944 if(left
== right
|| top
== bottom
) return FALSE
;
946 emr
.emr
.iType
= EMR_RECTANGLE
;
947 emr
.emr
.nSize
= sizeof(emr
);
948 emr
.rclBox
.left
= min( left
, right
);
949 emr
.rclBox
.top
= min( top
, bottom
);
950 emr
.rclBox
.right
= max( left
, right
);
951 emr
.rclBox
.bottom
= max( top
, bottom
);
952 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
957 return emfdc_record( emf
, &emr
.emr
);
960 BOOL
EMFDC_RoundRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
,
961 INT bottom
, INT ell_width
, INT ell_height
)
963 struct emf
*emf
= get_dc_emf( dc_attr
);
966 if (left
== right
|| top
== bottom
) return FALSE
;
968 emr
.emr
.iType
= EMR_ROUNDRECT
;
969 emr
.emr
.nSize
= sizeof(emr
);
970 emr
.rclBox
.left
= min( left
, right
);
971 emr
.rclBox
.top
= min( top
, bottom
);
972 emr
.rclBox
.right
= max( left
, right
);
973 emr
.rclBox
.bottom
= max( top
, bottom
);
974 emr
.szlCorner
.cx
= ell_width
;
975 emr
.szlCorner
.cy
= ell_height
;
976 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
981 return emfdc_record( emf
, &emr
.emr
);
984 BOOL
EMFDC_SetPixel( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
)
988 emr
.emr
.iType
= EMR_SETPIXELV
;
989 emr
.emr
.nSize
= sizeof(emr
);
993 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
996 static BOOL
emfdc_polylinegon( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
, DWORD type
)
998 struct emf
*emf
= get_dc_emf( dc_attr
);
1001 BOOL ret
, use_small_emr
= can_use_short_points( points
, count
);
1003 size
= use_small_emr
? offsetof( EMRPOLYLINE16
, apts
[count
] ) : offsetof( EMRPOLYLINE
, aptl
[count
] );
1005 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1006 emr
->emr
.iType
= use_small_emr
? type
+ EMR_POLYLINE16
- EMR_POLYLINE
: type
;
1007 emr
->emr
.nSize
= size
;
1010 store_points( emr
->aptl
, points
, count
, use_small_emr
);
1013 get_points_bounds( &emr
->rclBounds
, points
, count
,
1014 (type
== EMR_POLYBEZIERTO
|| type
== EMR_POLYLINETO
) ? dc_attr
: 0 );
1016 emr
->rclBounds
= empty_bounds
;
1018 ret
= emfdc_record( emf
, &emr
->emr
);
1019 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1020 HeapFree( GetProcessHeap(), 0, emr
);
1024 BOOL
EMFDC_Polyline( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1026 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINE
);
1029 BOOL
EMFDC_PolylineTo( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1031 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINETO
);
1034 BOOL
EMFDC_Polygon( DC_ATTR
*dc_attr
, const POINT
*pt
, INT count
)
1036 if(count
< 2) return FALSE
;
1037 return emfdc_polylinegon( dc_attr
, pt
, count
, EMR_POLYGON
);
1040 BOOL
EMFDC_PolyBezier( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1042 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIER
);
1045 BOOL
EMFDC_PolyBezierTo( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1047 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIERTO
);
1050 static BOOL
emfdc_poly_polylinegon( struct emf
*emf
, const POINT
*pt
, const INT
*counts
,
1051 UINT polys
, DWORD type
)
1053 EMRPOLYPOLYLINE
*emr
;
1054 DWORD cptl
= 0, poly
, size
;
1055 BOOL ret
, use_small_emr
, bounds_valid
= TRUE
;
1057 for(poly
= 0; poly
< polys
; poly
++) {
1058 cptl
+= counts
[poly
];
1059 if(counts
[poly
] < 2) bounds_valid
= FALSE
;
1061 if(!cptl
) bounds_valid
= FALSE
;
1062 use_small_emr
= can_use_short_points( pt
, cptl
);
1064 size
= FIELD_OFFSET(EMRPOLYPOLYLINE
, aPolyCounts
[polys
]);
1066 size
+= cptl
* sizeof(POINTS
);
1068 size
+= cptl
* sizeof(POINTL
);
1070 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1072 emr
->emr
.iType
= type
;
1073 if(use_small_emr
) emr
->emr
.iType
+= EMR_POLYPOLYLINE16
- EMR_POLYPOLYLINE
;
1075 emr
->emr
.nSize
= size
;
1076 if(bounds_valid
&& !emf
->path
)
1077 get_points_bounds( &emr
->rclBounds
, pt
, cptl
, 0 );
1079 emr
->rclBounds
= empty_bounds
;
1080 emr
->nPolys
= polys
;
1085 memcpy( emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
) );
1086 store_points( (POINTL
*)(emr
->aPolyCounts
+ polys
), pt
, cptl
, use_small_emr
);
1089 ret
= emfdc_record( emf
, &emr
->emr
);
1090 if(ret
&& !bounds_valid
)
1093 SetLastError( ERROR_INVALID_PARAMETER
);
1095 if(ret
&& !emf
->path
)
1096 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1097 HeapFree( GetProcessHeap(), 0, emr
);
1101 BOOL
EMFDC_PolyPolyline( DC_ATTR
*dc_attr
, const POINT
*pt
, const DWORD
*counts
, DWORD polys
)
1103 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, (const INT
*)counts
, polys
, EMR_POLYPOLYLINE
);
1106 BOOL
EMFDC_PolyPolygon( DC_ATTR
*dc_attr
, const POINT
*pt
, const INT
*counts
, UINT polys
)
1108 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, counts
, polys
, EMR_POLYPOLYGON
);
1111 BOOL
EMFDC_PolyDraw( DC_ATTR
*dc_attr
, const POINT
*pts
, const BYTE
*types
, DWORD count
)
1113 struct emf
*emf
= get_dc_emf( dc_attr
);
1117 BOOL use_small_emr
= can_use_short_points( pts
, count
);
1120 size
= use_small_emr
? offsetof( EMRPOLYDRAW16
, apts
[count
] )
1121 : offsetof( EMRPOLYDRAW
, aptl
[count
] );
1122 size
+= (count
+ 3) & ~3;
1124 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1126 emr
->emr
.iType
= use_small_emr
? EMR_POLYDRAW16
: EMR_POLYDRAW
;
1127 emr
->emr
.nSize
= size
;
1130 types_dest
= store_points( emr
->aptl
, pts
, count
, use_small_emr
);
1131 memcpy( types_dest
, types
, count
);
1132 if (count
& 3) memset( types_dest
+ count
, 0, 4 - (count
& 3) );
1135 get_points_bounds( &emr
->rclBounds
, pts
, count
, 0 );
1137 emr
->rclBounds
= empty_bounds
;
1139 ret
= emfdc_record( emf
, &emr
->emr
);
1140 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1141 HeapFree( GetProcessHeap(), 0, emr
);
1145 BOOL
EMFDC_ExtFloodFill( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
, UINT fill_type
)
1147 EMREXTFLOODFILL emr
;
1149 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
1150 emr
.emr
.nSize
= sizeof(emr
);
1153 emr
.crColor
= color
;
1154 emr
.iMode
= fill_type
;
1155 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
1158 BOOL
EMFDC_FillRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
)
1160 struct emf
*emf
= get_dc_emf( dc_attr
);
1162 DWORD size
, rgnsize
, index
;
1165 if (!(index
= emfdc_create_brush( emf
, hbrush
))) return FALSE
;
1167 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1168 size
= rgnsize
+ offsetof(EMRFILLRGN
,RgnData
);
1169 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1171 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1173 emr
->emr
.iType
= EMR_FILLRGN
;
1174 emr
->emr
.nSize
= size
;
1175 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1176 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1177 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1178 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1179 emr
->cbRgnData
= rgnsize
;
1180 emr
->ihBrush
= index
;
1182 ret
= emfdc_record( emf
, &emr
->emr
);
1183 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1184 HeapFree( GetProcessHeap(), 0, emr
);
1188 BOOL
EMFDC_FrameRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
1190 struct emf
*emf
= get_dc_emf( dc_attr
);
1192 DWORD size
, rgnsize
, index
;
1195 index
= emfdc_create_brush( emf
, hbrush
);
1196 if(!index
) return FALSE
;
1198 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1199 size
= rgnsize
+ offsetof(EMRFRAMERGN
,RgnData
);
1200 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1202 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1204 emr
->emr
.iType
= EMR_FRAMERGN
;
1205 emr
->emr
.nSize
= size
;
1206 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1207 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1208 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1209 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1210 emr
->cbRgnData
= rgnsize
;
1211 emr
->ihBrush
= index
;
1212 emr
->szlStroke
.cx
= width
;
1213 emr
->szlStroke
.cy
= height
;
1215 ret
= emfdc_record( emf
, &emr
->emr
);
1216 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1217 HeapFree( GetProcessHeap(), 0, emr
);
1221 static BOOL
emfdc_paint_invert_region( struct emf
*emf
, HRGN hrgn
, DWORD iType
)
1224 DWORD size
, rgnsize
;
1227 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1228 size
= rgnsize
+ offsetof(EMRINVERTRGN
,RgnData
);
1229 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1231 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1233 emr
->emr
.iType
= iType
;
1234 emr
->emr
.nSize
= size
;
1235 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1236 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1237 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1238 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1239 emr
->cbRgnData
= rgnsize
;
1241 ret
= emfdc_record( emf
, &emr
->emr
);
1242 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1243 HeapFree( GetProcessHeap(), 0, emr
);
1247 BOOL
EMFDC_PaintRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1249 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_PAINTRGN
);
1252 BOOL
EMFDC_InvertRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1254 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_INVERTRGN
);
1257 BOOL
EMFDC_ExtTextOut( DC_ATTR
*dc_attr
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1258 const WCHAR
*str
, UINT count
, const INT
*dx
)
1260 struct emf
*emf
= get_dc_emf( dc_attr
);
1261 HDC hdc
= dc_attr_handle( dc_attr
);
1262 FLOAT ex_scale
, ey_scale
;
1263 EMREXTTEXTOUTW
*emr
;
1264 int text_height
= 0;
1270 size
= sizeof(*emr
) + ((count
+1) & ~1) * sizeof(WCHAR
) + count
* sizeof(INT
);
1272 TRACE( "%s %s count %d size = %ld\n", debugstr_wn(str
, count
),
1273 wine_dbgstr_rect(rect
), count
, size
);
1274 emr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1276 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1278 HDC hdc
= dc_attr_handle( dc_attr
);
1279 const INT horzSize
= GetDeviceCaps( hdc
, HORZSIZE
);
1280 const INT horzRes
= GetDeviceCaps( hdc
, HORZRES
);
1281 const INT vertSize
= GetDeviceCaps( hdc
, VERTSIZE
);
1282 const INT vertRes
= GetDeviceCaps( hdc
, VERTRES
);
1283 SIZE wndext
, vportext
;
1285 GetViewportExtEx( hdc
, &vportext
);
1286 GetWindowExtEx( hdc
, &wndext
);
1287 ex_scale
= 100.0 * ((FLOAT
)horzSize
/ (FLOAT
)horzRes
) /
1288 ((FLOAT
)wndext
.cx
/ (FLOAT
)vportext
.cx
);
1289 ey_scale
= 100.0 * ((FLOAT
)vertSize
/ (FLOAT
)vertRes
) /
1290 ((FLOAT
)wndext
.cy
/ (FLOAT
)vportext
.cy
);
1298 emr
->emr
.iType
= EMR_EXTTEXTOUTW
;
1299 emr
->emr
.nSize
= size
;
1300 emr
->iGraphicsMode
= dc_attr
->graphics_mode
;
1301 emr
->exScale
= ex_scale
;
1302 emr
->eyScale
= ey_scale
;
1303 emr
->emrtext
.ptlReference
.x
= x
;
1304 emr
->emrtext
.ptlReference
.y
= y
;
1305 emr
->emrtext
.nChars
= count
;
1306 emr
->emrtext
.offString
= sizeof(*emr
);
1307 memcpy( (char*)emr
+ emr
->emrtext
.offString
, str
, count
* sizeof(WCHAR
) );
1308 emr
->emrtext
.fOptions
= flags
;
1311 emr
->emrtext
.rcl
.left
= emr
->emrtext
.rcl
.top
= 0;
1312 emr
->emrtext
.rcl
.right
= emr
->emrtext
.rcl
.bottom
= -1;
1316 emr
->emrtext
.rcl
.left
= rect
->left
;
1317 emr
->emrtext
.rcl
.top
= rect
->top
;
1318 emr
->emrtext
.rcl
.right
= rect
->right
;
1319 emr
->emrtext
.rcl
.bottom
= rect
->bottom
;
1322 emr
->emrtext
.offDx
= emr
->emrtext
.offString
+ ((count
+1) & ~1) * sizeof(WCHAR
);
1327 memcpy( (char*)emr
+ emr
->emrtext
.offDx
, dx
, count
* sizeof(INT
) );
1328 for (i
= 0; i
< count
; i
++) text_width
+= dx
[i
];
1329 if (GetTextExtentPoint32W( hdc
, str
, count
, &str_size
))
1330 text_height
= str_size
.cy
;
1335 INT
*emf_dx
= (INT
*)((char*)emr
+ emr
->emrtext
.offDx
);
1337 for (i
= 0; i
< count
; i
++)
1339 if (GetTextExtentPoint32W( hdc
, str
+ i
, 1, &charSize
))
1341 emf_dx
[i
] = charSize
.cx
;
1342 text_width
+= charSize
.cx
;
1343 text_height
= max( text_height
, charSize
.cy
);
1350 emr
->rclBounds
.left
= emr
->rclBounds
.top
= 0;
1351 emr
->rclBounds
.right
= emr
->rclBounds
.bottom
= -1;
1355 /* FIXME: handle font escapement */
1356 switch (dc_attr
->text_align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1359 emr
->rclBounds
.left
= x
- (text_width
/ 2) - 1;
1360 emr
->rclBounds
.right
= x
+ (text_width
/ 2) + 1;
1364 emr
->rclBounds
.left
= x
- text_width
- 1;
1365 emr
->rclBounds
.right
= x
;
1368 default: /* TA_LEFT */
1369 emr
->rclBounds
.left
= x
;
1370 emr
->rclBounds
.right
= x
+ text_width
+ 1;
1373 switch (dc_attr
->text_align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1376 if (!GetTextMetricsW( hdc
, &tm
)) tm
.tmDescent
= 0;
1377 /* Play safe here... it's better to have a bounding box */
1378 /* that is too big than too small. */
1379 emr
->rclBounds
.top
= y
- text_height
- 1;
1380 emr
->rclBounds
.bottom
= y
+ tm
.tmDescent
+ 1;
1384 emr
->rclBounds
.top
= y
- text_height
- 1;
1385 emr
->rclBounds
.bottom
= y
;
1388 default: /* TA_TOP */
1389 emr
->rclBounds
.top
= y
;
1390 emr
->rclBounds
.bottom
= y
+ text_height
+ 1;
1392 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1395 ret
= emfdc_record( emf
, &emr
->emr
);
1396 HeapFree( GetProcessHeap(), 0, emr
);
1400 BOOL
EMFDC_GradientFill( DC_ATTR
*dc_attr
, TRIVERTEX
*vert_array
, ULONG nvert
,
1401 void *grad_array
, ULONG ngrad
, ULONG mode
)
1403 EMRGRADIENTFILL
*emr
;
1404 ULONG i
, pt
, size
, num_pts
= ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2);
1405 const ULONG
*pts
= (const ULONG
*)grad_array
;
1408 size
= FIELD_OFFSET(EMRGRADIENTFILL
, Ver
[nvert
]) + num_pts
* sizeof(pts
[0]);
1410 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1411 if (!emr
) return FALSE
;
1413 for (i
= 0; i
< num_pts
; i
++)
1419 emr
->rclBounds
.left
= emr
->rclBounds
.right
= vert_array
[pt
].x
;
1420 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1424 if (vert_array
[pt
].x
< emr
->rclBounds
.left
)
1425 emr
->rclBounds
.left
= vert_array
[pt
].x
;
1426 else if (vert_array
[pt
].x
> emr
->rclBounds
.right
)
1427 emr
->rclBounds
.right
= vert_array
[pt
].x
;
1428 if (vert_array
[pt
].y
< emr
->rclBounds
.top
)
1429 emr
->rclBounds
.top
= vert_array
[pt
].y
;
1430 else if (vert_array
[pt
].y
> emr
->rclBounds
.bottom
)
1431 emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1434 emr
->rclBounds
.right
--;
1435 emr
->rclBounds
.bottom
--;
1437 emr
->emr
.iType
= EMR_GRADIENTFILL
;
1438 emr
->emr
.nSize
= size
;
1442 memcpy( emr
->Ver
, vert_array
, nvert
* sizeof(vert_array
[0]) );
1443 memcpy( emr
->Ver
+ nvert
, pts
, num_pts
* sizeof(pts
[0]) );
1445 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1446 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1447 HeapFree( GetProcessHeap(), 0, emr
);
1451 BOOL
EMFDC_FillPath( DC_ATTR
*dc_attr
)
1453 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_FILLPATH
);
1456 BOOL
EMFDC_StrokeAndFillPath( DC_ATTR
*dc_attr
)
1458 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEANDFILLPATH
);
1461 BOOL
EMFDC_StrokePath( DC_ATTR
*dc_attr
)
1463 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEPATH
);
1466 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1467 static BOOL
emfdrv_stretchblt( struct emf
*emf
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1468 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1469 DWORD rop
, DWORD type
)
1471 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1472 UINT bmi_size
, emr_size
, size
;
1473 HBITMAP bitmap
, blit_bitmap
= NULL
;
1474 EMRBITBLT
*emr
= NULL
;
1479 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1482 blit_bitmap
= bitmap
;
1483 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1485 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1486 emr_size
= type
== EMR_BITBLT
? sizeof(EMRBITBLT
) : sizeof(EMRSTRETCHBLT
);
1487 size
= emr_size
+ bmi_size
+ src_info
.bmiHeader
.biSizeImage
;
1489 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1491 emr
->emr
.iType
= type
;
1492 emr
->emr
.nSize
= size
;
1493 emr
->rclBounds
.left
= x_dst
;
1494 emr
->rclBounds
.top
= y_dst
;
1495 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1496 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1499 emr
->cxDest
= width_dst
;
1500 emr
->cyDest
= height_dst
;
1503 if (type
!= EMR_BITBLT
)
1505 EMRSTRETCHBLT
*emr_stretchblt
= (EMRSTRETCHBLT
*)emr
;
1506 emr_stretchblt
->cxSrc
= width_src
;
1507 emr_stretchblt
->cySrc
= height_src
;
1510 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1511 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1512 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1513 emr
->offBmiSrc
= emr_size
;
1514 emr
->cbBmiSrc
= bmi_size
;
1515 emr
->offBitsSrc
= emr_size
+ bmi_size
;
1516 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1518 bmi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1519 bmi
->bmiHeader
= src_info
.bmiHeader
;
1520 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1521 (BYTE
*)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1524 ret
= emfdc_record( emf
, (EMR
*)emr
);
1525 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1529 HeapFree( GetProcessHeap(), 0, emr
);
1530 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1531 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1535 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1536 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1537 BLENDFUNCTION blend_function
)
1539 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
,
1540 x_src
, y_src
, width_src
, height_src
, *(DWORD
*)&blend_function
,
1544 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1546 struct emf
*emf
= get_dc_emf( dc_attr
);
1550 emr
.emr
.iType
= EMR_BITBLT
;
1551 emr
.emr
.nSize
= sizeof(emr
);
1552 emr
.rclBounds
.left
= left
;
1553 emr
.rclBounds
.top
= top
;
1554 emr
.rclBounds
.right
= left
+ width
- 1;
1555 emr
.rclBounds
.bottom
= top
+ height
- 1;
1559 emr
.cyDest
= height
;
1563 emr
.xformSrc
.eM11
= 1.0;
1564 emr
.xformSrc
.eM12
= 0.0;
1565 emr
.xformSrc
.eM21
= 0.0;
1566 emr
.xformSrc
.eM22
= 1.0;
1567 emr
.xformSrc
.eDx
= 0.0;
1568 emr
.xformSrc
.eDy
= 0.0;
1569 emr
.crBkColorSrc
= 0;
1576 ret
= emfdc_record( emf
, &emr
.emr
);
1577 if (ret
) emfdc_update_bounds( emf
, &emr
.rclBounds
);
1581 static inline BOOL
rop_uses_src( DWORD rop
)
1583 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
1586 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
1587 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
1589 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
1590 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width
, height
,
1591 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
1594 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1595 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1598 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1599 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1600 hdc_src
, x_src
, y_src
, width_src
,
1601 height_src
, rop
, EMR_STRETCHBLT
);
1604 BOOL
EMFDC_TransparentBlt( DC_ATTR
*dc_attr
, int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1605 HDC hdc_src
, int x_src
, int y_src
, int width_src
, int height_src
,
1608 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1609 hdc_src
, x_src
, y_src
, width_src
,
1610 height_src
, color
, EMR_TRANSPARENTBLT
);
1613 BOOL
EMFDC_MaskBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1614 HDC hdc_src
, INT x_src
, INT y_src
, HBITMAP mask
,
1615 INT x_mask
, INT y_mask
, DWORD rop
)
1617 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1618 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1619 struct emf
*emf
= get_dc_emf( dc_attr
);
1620 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1621 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1622 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1623 UINT bmi_size
, size
, mask_info_size
= 0;
1624 EMRMASKBLT
*emr
= NULL
;
1626 HDC blit_dc
, mask_dc
= NULL
;
1629 if (!rop_uses_src( rop
))
1630 return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1632 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1634 blit_bitmap
= bitmap
;
1635 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1641 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1642 if (mask_info
.bmiHeader
.biBitCount
== 1)
1643 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1645 else mask_info
.bmiHeader
.biSizeImage
= 0;
1647 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1648 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1650 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1652 emr
->emr
.iType
= EMR_MASKBLT
;
1653 emr
->emr
.nSize
= size
;
1654 emr
->rclBounds
.left
= x_dst
;
1655 emr
->rclBounds
.top
= y_dst
;
1656 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1657 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1660 emr
->cxDest
= width_dst
;
1661 emr
->cyDest
= height_dst
;
1665 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1666 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1667 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1668 emr
->offBmiSrc
= sizeof(*emr
);
1669 emr
->cbBmiSrc
= bmi_size
;
1670 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1671 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1672 emr
->xMask
= x_mask
;
1673 emr
->yMask
= y_mask
;
1674 emr
->iUsageMask
= DIB_PAL_INDICES
;
1675 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1676 emr
->cbBmiMask
= mask_info_size
;
1677 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1678 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1680 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1681 bmi
->bmiHeader
= src_info
.bmiHeader
;
1682 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1683 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1688 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1689 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1690 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1691 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1696 ret
= emfdc_record( emf
, (EMR
*)emr
);
1697 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1701 HeapFree( GetProcessHeap(), 0, emr
);
1702 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1703 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1704 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1705 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1709 BOOL
EMFDC_PlgBlt( DC_ATTR
*dc_attr
, const POINT
*points
, HDC hdc_src
, INT x_src
, INT y_src
,
1710 INT width
, INT height
, HBITMAP mask
, INT x_mask
, INT y_mask
)
1712 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1713 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1714 struct emf
*emf
= get_dc_emf( dc_attr
);
1715 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1716 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1717 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1718 UINT bmi_size
, size
, mask_info_size
= 0;
1719 EMRPLGBLT
*emr
= NULL
;
1721 HDC blit_dc
, mask_dc
= NULL
;
1722 int x_min
, y_min
, x_max
, y_max
, i
;
1725 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1728 blit_bitmap
= bitmap
;
1729 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1735 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1736 if (mask_info
.bmiHeader
.biBitCount
== 1)
1737 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1739 else mask_info
.bmiHeader
.biSizeImage
= 0;
1741 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1742 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1744 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1746 emr
->emr
.iType
= EMR_PLGBLT
;
1747 emr
->emr
.nSize
= size
;
1749 /* FIXME: not exactly what native does */
1750 x_min
= x_max
= points
[1].x
+ points
[2].x
- points
[0].x
;
1751 y_min
= y_max
= points
[1].y
+ points
[2].y
- points
[0].y
;
1752 for (i
= 0; i
< ARRAYSIZE(emr
->aptlDest
); i
++)
1754 x_min
= min( x_min
, points
[i
].x
);
1755 y_min
= min( y_min
, points
[i
].y
);
1756 x_max
= max( x_max
, points
[i
].x
);
1757 y_max
= max( y_min
, points
[i
].y
);
1759 emr
->rclBounds
.left
= x_min
;
1760 emr
->rclBounds
.top
= y_min
;
1761 emr
->rclBounds
.right
= x_max
;
1762 emr
->rclBounds
.bottom
= y_max
;
1763 memcpy( emr
->aptlDest
, points
, sizeof(emr
->aptlDest
) );
1767 emr
->cySrc
= height
;
1768 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1769 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1770 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1771 emr
->offBmiSrc
= sizeof(*emr
);
1772 emr
->cbBmiSrc
= bmi_size
;
1773 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1774 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1775 emr
->xMask
= x_mask
;
1776 emr
->yMask
= y_mask
;
1777 emr
->iUsageMask
= DIB_PAL_INDICES
;
1778 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1779 emr
->cbBmiMask
= mask_info_size
;
1780 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1781 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1783 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1784 bmi
->bmiHeader
= src_info
.bmiHeader
;
1785 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1786 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1791 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1792 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1793 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1794 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1799 ret
= emfdc_record( emf
, (EMR
*)emr
);
1800 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1804 HeapFree( GetProcessHeap(), 0, emr
);
1805 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1806 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1807 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1808 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1812 BOOL
EMFDC_StretchDIBits( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1813 INT x_src
, INT y_src
, INT width_src
, INT height_src
, const void *bits
,
1814 const BITMAPINFO
*info
, UINT usage
, DWORD rop
)
1816 EMRSTRETCHDIBITS
*emr
;
1818 UINT bmi_size
, img_size
, payload_size
, emr_size
;
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 /* check for overflows */
1827 payload_size
= bmi_size
+ img_size
;
1828 if (payload_size
< bmi_size
) return 0;
1830 emr_size
= sizeof (EMRSTRETCHDIBITS
) + payload_size
;
1831 if (emr_size
< sizeof (EMRSTRETCHDIBITS
)) return 0;
1833 /* allocate record */
1834 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
))) return 0;
1836 /* write a bitmap info header (with colours) to the record */
1837 bi
= (BITMAPINFO
*)&emr
[1];
1838 bi
->bmiHeader
= bih
;
1839 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1841 /* write bitmap bits to the record */
1842 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1844 /* fill in the EMR header at the front of our piece of memory */
1845 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
1846 emr
->emr
.nSize
= emr_size
;
1850 emr
->cxDest
= width_dst
;
1851 emr
->cyDest
= height_dst
;
1856 emr
->iUsageSrc
= usage
;
1857 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
1858 emr
->cbBmiSrc
= bmi_size
;
1859 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1860 emr
->cbBitsSrc
= img_size
;
1862 emr
->cxSrc
= width_src
;
1863 emr
->cySrc
= height_src
;
1865 emr
->rclBounds
.left
= x_dst
;
1866 emr
->rclBounds
.top
= y_dst
;
1867 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1868 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1870 /* save the record we just created */
1871 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1872 if (ret
) emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1873 HeapFree( GetProcessHeap(), 0, emr
);
1877 BOOL
EMFDC_SetDIBitsToDevice( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, DWORD width
, DWORD height
,
1878 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
1879 const void *bits
, const BITMAPINFO
*info
, UINT usage
)
1881 EMRSETDIBITSTODEVICE
*emr
;
1883 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1884 UINT src_height
, stride
;
1885 BITMAPINFOHEADER bih
;
1888 /* calculate the size of the colour table and the image */
1889 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1890 &bmi_size
, &img_size
)) return 0;
1892 if (bih
.biHeight
>= 0)
1894 src_height
= (UINT
)bih
.biHeight
;
1895 if (src_height
> y_src
+ height
) src_height
= y_src
+ height
;
1897 if (src_height
< startscan
) lines
= 0;
1898 else if (lines
> src_height
- startscan
) lines
= src_height
- startscan
;
1900 if (!lines
) return 0;
1902 if (bih
.biCompression
== BI_RGB
|| bih
.biCompression
== BI_BITFIELDS
)
1904 /* truncate image and check for overflows */
1905 stride
= get_dib_stride( bih
.biWidth
, bih
.biBitCount
);
1906 img_size
= lines
* stride
;
1907 if (img_size
/ stride
!= lines
) return 0;
1911 /* check for overflows */
1912 payload_size
= bmi_size
+ img_size
;
1913 if (payload_size
< bmi_size
) return 0;
1915 emr_size
= sizeof (EMRSETDIBITSTODEVICE
) + payload_size
;
1916 if (emr_size
< sizeof (EMRSETDIBITSTODEVICE
)) return 0;
1918 /* allocate record */
1919 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, emr_size
))) return FALSE
;
1921 /* write a bitmap info header (with colours) to the record */
1922 bi
= (BITMAPINFO
*)&emr
[1];
1923 bi
->bmiHeader
= bih
;
1924 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1926 /* write bitmap bits to the record */
1927 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1929 emr
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
1930 emr
->emr
.nSize
= emr_size
;
1931 emr
->rclBounds
.left
= x_dst
;
1932 emr
->rclBounds
.top
= y_dst
;
1933 emr
->rclBounds
.right
= x_dst
+ width
- 1;
1934 emr
->rclBounds
.bottom
= y_dst
+ height
- 1;
1940 emr
->cySrc
= height
;
1941 emr
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
1942 emr
->cbBmiSrc
= bmi_size
;
1943 emr
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + bmi_size
;
1944 emr
->cbBitsSrc
= img_size
;
1945 emr
->iUsageSrc
= usage
;
1946 emr
->iStartScan
= startscan
;
1947 emr
->cScans
= lines
;
1949 if ((ret
= emfdc_record( get_dc_emf( dc_attr
), (EMR
*)emr
)))
1950 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1952 HeapFree( GetProcessHeap(), 0, emr
);
1956 BOOL
EMFDC_SetDCBrushColor( DC_ATTR
*dc_attr
, COLORREF color
)
1958 struct emf
*emf
= get_dc_emf( dc_attr
);
1959 HDC hdc
= dc_attr_handle( dc_attr
);
1960 EMRSELECTOBJECT emr
;
1963 if (GetCurrentObject( hdc
, OBJ_BRUSH
) != GetStockObject( DC_BRUSH
)) return TRUE
;
1965 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
1966 if (!(emf
->dc_brush
= CreateSolidBrush( color
))) return FALSE
;
1967 if (!(index
= emfdc_create_brush( emf
, emf
->dc_brush
))) return FALSE
;
1968 GDI_hdc_using_object( emf
->dc_brush
, hdc
, emfdc_delete_object
);
1969 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1970 emr
.emr
.nSize
= sizeof(emr
);
1971 emr
.ihObject
= index
;
1972 return emfdc_record( emf
, &emr
.emr
);
1975 BOOL
EMFDC_SetDCPenColor( DC_ATTR
*dc_attr
, COLORREF color
)
1977 struct emf
*emf
= get_dc_emf( dc_attr
);
1978 HDC hdc
= dc_attr_handle( dc_attr
);
1979 EMRSELECTOBJECT emr
;
1981 LOGPEN logpen
= { PS_SOLID
, { 0, 0 }, color
};
1983 if (GetCurrentObject( hdc
, OBJ_PEN
) != GetStockObject( DC_PEN
)) return TRUE
;
1985 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
1986 if (!(emf
->dc_pen
= CreatePenIndirect( &logpen
))) return FALSE
;
1987 if (!(index
= emfdc_create_pen( emf
, emf
->dc_pen
))) return FALSE
;
1988 GDI_hdc_using_object( emf
->dc_pen
, hdc
, emfdc_delete_object
);
1989 emr
.emr
.iType
= EMR_SELECTOBJECT
;
1990 emr
.emr
.nSize
= sizeof(emr
);
1991 emr
.ihObject
= index
;
1992 return emfdc_record( emf
, &emr
.emr
);
1995 BOOL
EMFDC_SaveDC( DC_ATTR
*dc_attr
)
1999 emr
.emr
.iType
= EMR_SAVEDC
;
2000 emr
.emr
.nSize
= sizeof(emr
);
2001 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2004 BOOL
EMFDC_RestoreDC( DC_ATTR
*dc_attr
, INT level
)
2008 if (abs(level
) > dc_attr
->save_level
|| level
== 0) return FALSE
;
2010 emr
.emr
.iType
= EMR_RESTOREDC
;
2011 emr
.emr
.nSize
= sizeof(emr
);
2013 emr
.iRelative
= level
;
2015 emr
.iRelative
= level
- dc_attr
->save_level
- 1;
2016 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2019 BOOL
EMFDC_SetTextAlign( DC_ATTR
*dc_attr
, UINT align
)
2021 EMRSETTEXTALIGN emr
;
2023 emr
.emr
.iType
= EMR_SETTEXTALIGN
;
2024 emr
.emr
.nSize
= sizeof(emr
);
2026 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2029 BOOL
EMFDC_SetTextJustification( DC_ATTR
*dc_attr
, INT extra
, INT breaks
)
2031 EMRSETTEXTJUSTIFICATION emr
;
2033 emr
.emr
.iType
= EMR_SETTEXTJUSTIFICATION
;
2034 emr
.emr
.nSize
= sizeof(emr
);
2035 emr
.nBreakExtra
= extra
;
2036 emr
.nBreakCount
= breaks
;
2037 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2040 BOOL
EMFDC_SetBkMode( DC_ATTR
*dc_attr
, INT mode
)
2044 emr
.emr
.iType
= EMR_SETBKMODE
;
2045 emr
.emr
.nSize
= sizeof(emr
);
2047 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2050 BOOL
EMFDC_SetBkColor( DC_ATTR
*dc_attr
, COLORREF color
)
2054 emr
.emr
.iType
= EMR_SETBKCOLOR
;
2055 emr
.emr
.nSize
= sizeof(emr
);
2056 emr
.crColor
= color
;
2057 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2061 BOOL
EMFDC_SetTextColor( DC_ATTR
*dc_attr
, COLORREF color
)
2063 EMRSETTEXTCOLOR emr
;
2065 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
2066 emr
.emr
.nSize
= sizeof(emr
);
2067 emr
.crColor
= color
;
2068 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2071 BOOL
EMFDC_SetROP2( DC_ATTR
*dc_attr
, INT rop
)
2075 emr
.emr
.iType
= EMR_SETROP2
;
2076 emr
.emr
.nSize
= sizeof(emr
);
2078 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2081 BOOL
EMFDC_SetPolyFillMode( DC_ATTR
*dc_attr
, INT mode
)
2083 EMRSETPOLYFILLMODE emr
;
2085 emr
.emr
.iType
= EMR_SETPOLYFILLMODE
;
2086 emr
.emr
.nSize
= sizeof(emr
);
2088 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2091 BOOL
EMFDC_SetStretchBltMode( DC_ATTR
*dc_attr
, INT mode
)
2093 EMRSETSTRETCHBLTMODE emr
;
2095 emr
.emr
.iType
= EMR_SETSTRETCHBLTMODE
;
2096 emr
.emr
.nSize
= sizeof(emr
);
2098 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2101 BOOL
EMFDC_SetArcDirection( DC_ATTR
*dc_attr
, INT dir
)
2103 EMRSETARCDIRECTION emr
;
2105 emr
.emr
.iType
= EMR_SETARCDIRECTION
;
2106 emr
.emr
.nSize
= sizeof(emr
);
2107 emr
.iArcDirection
= dir
;
2108 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2111 INT
EMFDC_ExcludeClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2113 EMREXCLUDECLIPRECT emr
;
2115 emr
.emr
.iType
= EMR_EXCLUDECLIPRECT
;
2116 emr
.emr
.nSize
= sizeof(emr
);
2117 emr
.rclClip
.left
= left
;
2118 emr
.rclClip
.top
= top
;
2119 emr
.rclClip
.right
= right
;
2120 emr
.rclClip
.bottom
= bottom
;
2121 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2124 BOOL
EMFDC_IntersectClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2126 EMRINTERSECTCLIPRECT emr
;
2128 emr
.emr
.iType
= EMR_INTERSECTCLIPRECT
;
2129 emr
.emr
.nSize
= sizeof(emr
);
2130 emr
.rclClip
.left
= left
;
2131 emr
.rclClip
.top
= top
;
2132 emr
.rclClip
.right
= right
;
2133 emr
.rclClip
.bottom
= bottom
;
2134 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2137 BOOL
EMFDC_OffsetClipRgn( DC_ATTR
*dc_attr
, INT x
, INT y
)
2139 EMROFFSETCLIPRGN emr
;
2141 emr
.emr
.iType
= EMR_OFFSETCLIPRGN
;
2142 emr
.emr
.nSize
= sizeof(emr
);
2143 emr
.ptlOffset
.x
= x
;
2144 emr
.ptlOffset
.y
= y
;
2145 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2148 BOOL
EMFDC_ExtSelectClipRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, INT mode
)
2150 EMREXTSELECTCLIPRGN
*emr
;
2151 DWORD size
, rgnsize
;
2156 if (mode
!= RGN_COPY
) return ERROR
;
2159 else rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
2161 size
= rgnsize
+ offsetof(EMREXTSELECTCLIPRGN
,RgnData
);
2162 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
2163 if (rgnsize
) NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
2165 emr
->emr
.iType
= EMR_EXTSELECTCLIPRGN
;
2166 emr
->emr
.nSize
= size
;
2167 emr
->cbRgnData
= rgnsize
;
2170 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2171 HeapFree( GetProcessHeap(), 0, emr
);
2175 BOOL
EMFDC_SetMapMode( DC_ATTR
*dc_attr
, INT mode
)
2179 emr
.emr
.iType
= EMR_SETMAPMODE
;
2180 emr
.emr
.nSize
= sizeof(emr
);
2182 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2185 BOOL
EMFDC_SetViewportExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2187 EMRSETVIEWPORTEXTEX emr
;
2189 emr
.emr
.iType
= EMR_SETVIEWPORTEXTEX
;
2190 emr
.emr
.nSize
= sizeof(emr
);
2191 emr
.szlExtent
.cx
= cx
;
2192 emr
.szlExtent
.cy
= cy
;
2193 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2196 BOOL
EMFDC_SetWindowExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2198 EMRSETWINDOWEXTEX emr
;
2200 emr
.emr
.iType
= EMR_SETWINDOWEXTEX
;
2201 emr
.emr
.nSize
= sizeof(emr
);
2202 emr
.szlExtent
.cx
= cx
;
2203 emr
.szlExtent
.cy
= cy
;
2204 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2207 BOOL
EMFDC_SetViewportOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2209 EMRSETVIEWPORTORGEX emr
;
2211 emr
.emr
.iType
= EMR_SETVIEWPORTORGEX
;
2212 emr
.emr
.nSize
= sizeof(emr
);
2213 emr
.ptlOrigin
.x
= x
;
2214 emr
.ptlOrigin
.y
= y
;
2215 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2218 BOOL
EMFDC_SetWindowOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2220 EMRSETWINDOWORGEX emr
;
2222 emr
.emr
.iType
= EMR_SETWINDOWORGEX
;
2223 emr
.emr
.nSize
= sizeof(emr
);
2224 emr
.ptlOrigin
.x
= x
;
2225 emr
.ptlOrigin
.y
= y
;
2226 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2229 BOOL
EMFDC_ScaleViewportExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2231 EMRSCALEVIEWPORTEXTEX emr
;
2233 emr
.emr
.iType
= EMR_SCALEVIEWPORTEXTEX
;
2234 emr
.emr
.nSize
= sizeof(emr
);
2236 emr
.xDenom
= x_denom
;
2238 emr
.yDenom
= y_denom
;
2239 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2242 BOOL
EMFDC_ScaleWindowExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2244 EMRSCALEWINDOWEXTEX emr
;
2246 emr
.emr
.iType
= EMR_SCALEWINDOWEXTEX
;
2247 emr
.emr
.nSize
= sizeof(emr
);
2249 emr
.xDenom
= x_denom
;
2251 emr
.yDenom
= y_denom
;
2252 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2255 BOOL
EMFDC_SetLayout( DC_ATTR
*dc_attr
, DWORD layout
)
2259 emr
.emr
.iType
= EMR_SETLAYOUT
;
2260 emr
.emr
.nSize
= sizeof(emr
);
2262 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2265 BOOL
EMFDC_SetWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
)
2267 EMRSETWORLDTRANSFORM emr
;
2269 emr
.emr
.iType
= EMR_SETWORLDTRANSFORM
;
2270 emr
.emr
.nSize
= sizeof(emr
);
2272 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2275 BOOL
EMFDC_ModifyWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
, DWORD mode
)
2277 EMRMODIFYWORLDTRANSFORM emr
;
2279 emr
.emr
.iType
= EMR_MODIFYWORLDTRANSFORM
;
2280 emr
.emr
.nSize
= sizeof(emr
);
2281 if (mode
== MWT_IDENTITY
)
2283 emr
.xform
.eM11
= 1.0f
;
2284 emr
.xform
.eM12
= 0.0f
;
2285 emr
.xform
.eM21
= 0.0f
;
2286 emr
.xform
.eM22
= 1.0f
;
2287 emr
.xform
.eDx
= 0.0f
;
2288 emr
.xform
.eDy
= 0.0f
;
2295 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2298 BOOL
EMFDC_SetMapperFlags( DC_ATTR
*dc_attr
, DWORD flags
)
2300 EMRSETMAPPERFLAGS emr
;
2302 emr
.emr
.iType
= EMR_SETMAPPERFLAGS
;
2303 emr
.emr
.nSize
= sizeof(emr
);
2304 emr
.dwFlags
= flags
;
2305 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2308 BOOL
EMFDC_AbortPath( DC_ATTR
*dc_attr
)
2310 struct emf
*emf
= get_dc_emf( dc_attr
);
2313 emr
.emr
.iType
= EMR_ABORTPATH
;
2314 emr
.emr
.nSize
= sizeof(emr
);
2317 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2320 BOOL
EMFDC_BeginPath( DC_ATTR
*dc_attr
)
2322 struct emf
*emf
= get_dc_emf( dc_attr
);
2325 emr
.emr
.iType
= EMR_BEGINPATH
;
2326 emr
.emr
.nSize
= sizeof(emr
);
2327 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
2333 BOOL
EMFDC_CloseFigure( DC_ATTR
*dc_attr
)
2337 emr
.emr
.iType
= EMR_CLOSEFIGURE
;
2338 emr
.emr
.nSize
= sizeof(emr
);
2339 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2342 BOOL
EMFDC_EndPath( DC_ATTR
*dc_attr
)
2344 struct emf
*emf
= get_dc_emf( dc_attr
);
2349 emr
.emr
.iType
= EMR_ENDPATH
;
2350 emr
.emr
.nSize
= sizeof(emr
);
2351 return emfdc_record( emf
, &emr
.emr
);
2354 BOOL
EMFDC_FlattenPath( DC_ATTR
*dc_attr
)
2358 emr
.emr
.iType
= EMR_FLATTENPATH
;
2359 emr
.emr
.nSize
= sizeof(emr
);
2360 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2363 BOOL
EMFDC_SelectClipPath( DC_ATTR
*dc_attr
, INT mode
)
2365 EMRSELECTCLIPPATH emr
;
2367 emr
.emr
.iType
= EMR_SELECTCLIPPATH
;
2368 emr
.emr
.nSize
= sizeof(emr
);
2370 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2373 BOOL
EMFDC_WidenPath( DC_ATTR
*dc_attr
)
2377 emr
.emr
.iType
= EMR_WIDENPATH
;
2378 emr
.emr
.nSize
= sizeof(emr
);
2379 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2382 void EMFDC_DeleteDC( DC_ATTR
*dc_attr
)
2384 struct emf
*emf
= get_dc_emf( dc_attr
);
2387 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2388 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2389 CloseHandle( emf
->file
);
2390 HeapFree( GetProcessHeap(), 0, emf
->palette
);
2391 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2392 for (index
= 0; index
< emf
->handles_size
; index
++)
2393 if (emf
->handles
[index
])
2394 GDI_hdc_not_using_object( emf
->handles
[index
], dc_attr_handle( emf
->dc_attr
));
2395 HeapFree( GetProcessHeap(), 0, emf
->handles
);
2396 HeapFree( GetProcessHeap(), 0, emf
);
2400 /*******************************************************************
2401 * GdiComment (GDI32.@)
2403 BOOL WINAPI
GdiComment( HDC hdc
, UINT bytes
, const BYTE
*buffer
)
2407 UINT total
, rounded_size
;
2410 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return FALSE
;
2412 rounded_size
= (bytes
+3) & ~3;
2413 total
= offsetof(EMRGDICOMMENT
,Data
) + rounded_size
;
2415 emr
= HeapAlloc(GetProcessHeap(), 0, total
);
2416 emr
->emr
.iType
= EMR_GDICOMMENT
;
2417 emr
->emr
.nSize
= total
;
2418 emr
->cbData
= bytes
;
2419 memset(&emr
->Data
[bytes
], 0, rounded_size
- bytes
);
2420 memcpy(&emr
->Data
[0], buffer
, bytes
);
2422 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2424 HeapFree(GetProcessHeap(), 0, emr
);
2429 /**********************************************************************
2430 * CreateEnhMetaFileA (GDI32.@)
2432 HDC WINAPI
CreateEnhMetaFileA( HDC hdc
, const char *filename
, const RECT
*rect
,
2433 const char *description
)
2435 WCHAR
*filenameW
= NULL
;
2436 WCHAR
*descriptionW
= NULL
;
2437 DWORD len1
, len2
, total
;
2442 total
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
2443 filenameW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2444 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, total
);
2449 len1
= strlen(description
);
2450 len2
= strlen(description
+ len1
+ 1);
2451 total
= MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, NULL
, 0 );
2452 descriptionW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2453 MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, descriptionW
, total
);
2456 ret
= CreateEnhMetaFileW( hdc
, filenameW
, rect
, descriptionW
);
2458 HeapFree( GetProcessHeap(), 0, filenameW
);
2459 HeapFree( GetProcessHeap(), 0, descriptionW
);
2463 /**********************************************************************
2464 * CreateEnhMetaFileW (GDI32.@)
2466 HDC WINAPI
CreateEnhMetaFileW( HDC hdc
, const WCHAR
*filename
, const RECT
*rect
,
2467 const WCHAR
*description
)
2473 DWORD size
= 0, length
= 0;
2475 TRACE( "(%p %s %s %s)\n", hdc
, debugstr_w(filename
), wine_dbgstr_rect(rect
),
2476 debugstr_w(description
) );
2478 if (!(ret
= NtGdiCreateMetafileDC( hdc
))) return 0;
2480 if (!(dc_attr
= get_dc_attr( ret
)) || !(emf
= HeapAlloc( GetProcessHeap(), 0, sizeof(*emf
) )))
2486 emf
->dc_attr
= dc_attr
;
2487 dc_attr
->emf
= (UINT_PTR
)emf
;
2489 if (description
) /* App name\0Title\0\0 */
2491 length
= lstrlenW( description
);
2492 length
+= lstrlenW( description
+ length
+ 1 );
2496 size
= sizeof(ENHMETAHEADER
) + (length
+ 3) / 4 * 4;
2498 if (!(emf
->emh
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
)))
2504 emf
->handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
2505 HANDLE_LIST_INC
* sizeof(emf
->handles
[0]) );
2506 emf
->handles_size
= HANDLE_LIST_INC
;
2507 emf
->cur_handles
= 1;
2512 emf
->palette_size
= 0;
2513 emf
->palette_used
= 0;
2514 emf
->palette
= NULL
;
2516 emf
->emh
->iType
= EMR_HEADER
;
2517 emf
->emh
->nSize
= size
;
2519 dc_attr
->emf_bounds
.left
= dc_attr
->emf_bounds
.top
= 0;
2520 dc_attr
->emf_bounds
.right
= dc_attr
->emf_bounds
.bottom
= -1;
2524 emf
->emh
->rclFrame
.left
= rect
->left
;
2525 emf
->emh
->rclFrame
.top
= rect
->top
;
2526 emf
->emh
->rclFrame
.right
= rect
->right
;
2527 emf
->emh
->rclFrame
.bottom
= rect
->bottom
;
2531 /* Set this to {0,0 - -1,-1} and update it at the end */
2532 emf
->emh
->rclFrame
.left
= emf
->emh
->rclFrame
.top
= 0;
2533 emf
->emh
->rclFrame
.right
= emf
->emh
->rclFrame
.bottom
= -1;
2536 emf
->emh
->dSignature
= ENHMETA_SIGNATURE
;
2537 emf
->emh
->nVersion
= 0x10000;
2538 emf
->emh
->nBytes
= emf
->emh
->nSize
;
2539 emf
->emh
->nRecords
= 1;
2540 emf
->emh
->nHandles
= 1;
2542 emf
->emh
->sReserved
= 0; /* According to docs, this is reserved and must be 0 */
2543 emf
->emh
->nDescription
= length
/ 2;
2545 emf
->emh
->offDescription
= length
? sizeof(ENHMETAHEADER
) : 0;
2547 emf
->emh
->nPalEntries
= 0; /* I guess this should start at 0 */
2549 /* Size in pixels */
2550 emf
->emh
->szlDevice
.cx
= GetDeviceCaps( ret
, HORZRES
);
2551 emf
->emh
->szlDevice
.cy
= GetDeviceCaps( ret
, VERTRES
);
2553 /* Size in millimeters */
2554 emf
->emh
->szlMillimeters
.cx
= GetDeviceCaps( ret
, HORZSIZE
);
2555 emf
->emh
->szlMillimeters
.cy
= GetDeviceCaps( ret
, VERTSIZE
);
2557 /* Size in micrometers */
2558 emf
->emh
->szlMicrometers
.cx
= emf
->emh
->szlMillimeters
.cx
* 1000;
2559 emf
->emh
->szlMicrometers
.cy
= emf
->emh
->szlMillimeters
.cy
* 1000;
2561 memcpy( (char *)emf
->emh
+ sizeof(ENHMETAHEADER
), description
, length
);
2563 if (filename
) /* disk based metafile */
2565 if ((file
= CreateFileW( filename
, GENERIC_WRITE
| GENERIC_READ
, 0,
2566 NULL
, CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
)
2574 TRACE( "returning %p\n", ret
);
2578 /******************************************************************
2579 * CloseEnhMetaFile (GDI32.@)
2581 HENHMETAFILE WINAPI
CloseEnhMetaFile( HDC hdc
)
2583 UINT size
, palette_size
;
2590 TRACE("(%p)\n", hdc
);
2592 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return 0;
2593 emf
= get_dc_emf( dc_attr
);
2595 palette_size
= emf
->palette_used
* sizeof(*emf
->palette
);
2596 size
= sizeof(*emr
) + palette_size
;
2597 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return 0;
2599 if (dc_attr
->save_level
)
2600 RestoreDC( hdc
, 1 );
2602 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2604 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2608 emr
->emr
.iType
= EMR_EOF
;
2609 emr
->emr
.nSize
= size
;
2610 emr
->nPalEntries
= emf
->palette_used
;
2611 emr
->offPalEntries
= FIELD_OFFSET(EMREOF
, nSizeLast
);
2612 memcpy( (BYTE
*)emr
+ emr
->offPalEntries
, emf
->palette
, palette_size
);
2614 ((DWORD
*)((BYTE
*)emr
+ size
))[-1] = size
;
2615 emfdc_record( emf
, &emr
->emr
);
2616 HeapFree( GetProcessHeap(), 0, emr
);
2618 emf
->emh
->rclBounds
= dc_attr
->emf_bounds
;
2620 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2621 if (emf
->emh
->rclFrame
.left
> emf
->emh
->rclFrame
.right
)
2623 emf
->emh
->rclFrame
.left
= emf
->emh
->rclBounds
.left
*
2624 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2625 emf
->emh
->rclFrame
.top
= emf
->emh
->rclBounds
.top
*
2626 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2627 emf
->emh
->rclFrame
.right
= emf
->emh
->rclBounds
.right
*
2628 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2629 emf
->emh
->rclFrame
.bottom
= emf
->emh
->rclBounds
.bottom
*
2630 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2633 if (emf
->file
) /* disk based metafile */
2635 if (!WriteFile( emf
->file
, emf
->emh
, emf
->emh
->nBytes
, NULL
, NULL
))
2637 CloseHandle( emf
->file
);
2641 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2642 mapping
= CreateFileMappingA( emf
->file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
2643 TRACE( "mapping = %p\n", mapping
);
2644 emf
->emh
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
2645 TRACE( "view = %p\n", emf
->emh
);
2646 CloseHandle( mapping
);
2647 CloseHandle( emf
->file
);
2650 hmf
= EMF_Create_HENHMETAFILE( emf
->emh
, emf
->emh
->nBytes
, emf
->file
!= 0 );
2652 emf
->emh
= NULL
; /* So it won't be deleted */