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
);
33 static inline UINT
aligned_size(UINT size
)
35 return (size
+ 3) & ~3;
38 static inline void pad_record(void *record
, UINT size
)
40 if (size
& 3) memset((char *)record
+ size
, 0, 4 - (size
& 3));
47 UINT handles_size
, cur_handles
;
55 PALETTEENTRY
*palette
;
70 EMRI_BW_FORM_METAFILE
,
76 EMRI_DESIGNVECTOR_EXT
,
81 } emfspool_record_type
;
83 #define HANDLE_LIST_INC 20
84 static const RECTL empty_bounds
= { 0, 0, -1, -1 };
86 static struct emf
*get_dc_emf( DC_ATTR
*dc_attr
)
88 return (struct emf
*)(UINT_PTR
)dc_attr
->emf
;
91 static HDC
dc_attr_handle( DC_ATTR
*dc_attr
)
93 return UlongToHandle( dc_attr
->hdc
);
96 static BOOL
emfdc_record( struct emf
*emf
, EMR
*emr
)
101 TRACE( "record %ld, size %ld\n", emr
->iType
, emr
->nSize
);
103 assert( !(emr
->nSize
& 3) );
105 emf
->emh
->nBytes
+= emr
->nSize
;
106 emf
->emh
->nRecords
++;
108 size
= HeapSize( GetProcessHeap(), 0, emf
->emh
);
109 len
= emf
->emh
->nBytes
;
112 size
+= (size
/ 2) + emr
->nSize
;
113 emh
= HeapReAlloc( GetProcessHeap(), 0, emf
->emh
, size
);
114 if (!emh
) return FALSE
;
117 memcpy( (char *)emf
->emh
+ emf
->emh
->nBytes
- emr
->nSize
, emr
, emr
->nSize
);
121 static void emfdc_update_bounds( struct emf
*emf
, RECTL
*rect
)
123 RECTL
*bounds
= &emf
->dc_attr
->emf_bounds
;
124 RECTL vport_rect
= *rect
;
126 LPtoDP( dc_attr_handle( emf
->dc_attr
), (POINT
*)&vport_rect
, 2 );
128 /* The coordinate systems may be mirrored
129 (LPtoDP handles points, not rectangles) */
130 if (vport_rect
.left
> vport_rect
.right
)
132 LONG temp
= vport_rect
.right
;
133 vport_rect
.right
= vport_rect
.left
;
134 vport_rect
.left
= temp
;
136 if (vport_rect
.top
> vport_rect
.bottom
)
138 LONG temp
= vport_rect
.bottom
;
139 vport_rect
.bottom
= vport_rect
.top
;
140 vport_rect
.top
= temp
;
143 if (bounds
->left
> bounds
->right
)
145 /* first bounding rectangle */
146 *bounds
= vport_rect
;
150 bounds
->left
= min(bounds
->left
, vport_rect
.left
);
151 bounds
->top
= min(bounds
->top
, vport_rect
.top
);
152 bounds
->right
= max(bounds
->right
, vport_rect
.right
);
153 bounds
->bottom
= max(bounds
->bottom
, vport_rect
.bottom
);
157 static UINT
get_bitmap_info( HDC
*hdc
, HBITMAP
*bitmap
, BITMAPINFO
*info
)
164 if (!(info_size
= GetObjectW( *bitmap
, sizeof(dib
), &dib
))) return 0;
166 if (info_size
== sizeof(dib
))
169 blit_bitmap
= *bitmap
;
173 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
174 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
175 BITMAP bmp
= dib
.dsBm
;
179 assert( info_size
== sizeof(BITMAP
) );
181 dib_info
->bmiHeader
.biSize
= sizeof(dib_info
->bmiHeader
);
182 dib_info
->bmiHeader
.biWidth
= bmp
.bmWidth
;
183 dib_info
->bmiHeader
.biHeight
= bmp
.bmHeight
;
184 dib_info
->bmiHeader
.biPlanes
= 1;
185 dib_info
->bmiHeader
.biBitCount
= bmp
.bmBitsPixel
;
186 dib_info
->bmiHeader
.biCompression
= BI_RGB
;
187 dib_info
->bmiHeader
.biSizeImage
= 0;
188 dib_info
->bmiHeader
.biXPelsPerMeter
= 0;
189 dib_info
->bmiHeader
.biYPelsPerMeter
= 0;
190 dib_info
->bmiHeader
.biClrUsed
= 0;
191 dib_info
->bmiHeader
.biClrImportant
= 0;
192 switch (dib_info
->bmiHeader
.biBitCount
)
195 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
196 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
197 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
200 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
201 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
202 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
205 if (dib_info
->bmiHeader
.biBitCount
> 8) break;
206 if (!(palette
= GetCurrentObject( *hdc
, OBJ_PAL
))) return FALSE
;
207 if (!GetPaletteEntries( palette
, 0, 256, (PALETTEENTRY
*)dib_info
->bmiColors
))
211 if (!(blit_dc
= NtGdiCreateCompatibleDC( *hdc
))) return FALSE
;
212 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
214 if (!SelectObject( blit_dc
, blit_bitmap
)) goto err
;
215 if (!BitBlt( blit_dc
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, *hdc
, 0, 0, SRCCOPY
))
218 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, info
, DIB_RGB_COLORS
))
221 bpp
= info
->bmiHeader
.biBitCount
;
223 return sizeof(BITMAPINFOHEADER
) + (1 << bpp
) * sizeof(RGBQUAD
);
224 else if (bpp
== 16 || bpp
== 32)
225 return sizeof(BITMAPINFOHEADER
) + 3 * sizeof(RGBQUAD
);
227 return sizeof(BITMAPINFOHEADER
);
230 if (blit_dc
&& blit_dc
!= *hdc
) DeleteDC( blit_dc
);
231 if (blit_bitmap
&& blit_bitmap
!= *bitmap
) DeleteObject( blit_bitmap
);
235 /*******************************************************************************************
236 * Verify that the DIB parameters are valid.
238 static BOOL
is_valid_dib_format( const BITMAPINFOHEADER
*info
, BOOL allow_compression
)
240 if (info
->biWidth
<= 0) return FALSE
;
241 if (info
->biHeight
== 0) return FALSE
;
243 if (allow_compression
&& (info
->biCompression
== BI_RLE4
|| info
->biCompression
== BI_RLE8
))
245 if (info
->biHeight
< 0) return FALSE
;
246 if (!info
->biSizeImage
) return FALSE
;
247 return info
->biBitCount
== (info
->biCompression
== BI_RLE4
? 4 : 8);
250 if (!info
->biPlanes
) return FALSE
;
252 /* check for size overflow */
253 if (!info
->biBitCount
) return FALSE
;
254 if (UINT_MAX
/ info
->biBitCount
< info
->biWidth
) return FALSE
;
255 if (UINT_MAX
/ get_dib_stride( info
->biWidth
, info
->biBitCount
) < abs( info
->biHeight
)) return FALSE
;
257 switch (info
->biBitCount
)
263 return (info
->biCompression
== BI_RGB
);
266 return (info
->biCompression
== BI_BITFIELDS
|| info
->biCompression
== BI_RGB
);
272 static BOOL
emf_parse_user_bitmapinfo( BITMAPINFOHEADER
*dst
, const BITMAPINFOHEADER
*info
,
273 UINT coloruse
, BOOL allow_compression
,
274 UINT
*bmi_size
, UINT
*img_size
)
276 UINT colour_table_size
;
278 if (coloruse
> DIB_PAL_COLORS
+ 1) return FALSE
; /* FIXME: handle DIB_PAL_COLORS+1 format */
279 if (!info
) return FALSE
;
281 memset(dst
, 0, sizeof(*dst
));
283 if (info
->biSize
== sizeof(BITMAPCOREHEADER
))
285 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
286 dst
->biWidth
= core
->bcWidth
;
287 dst
->biHeight
= core
->bcHeight
;
288 dst
->biPlanes
= core
->bcPlanes
;
289 dst
->biBitCount
= core
->bcBitCount
;
290 dst
->biCompression
= BI_RGB
;
291 dst
->biXPelsPerMeter
= 0;
292 dst
->biYPelsPerMeter
= 0;
294 dst
->biClrImportant
= 0;
296 else if (info
->biSize
>= sizeof(BITMAPINFOHEADER
)) /* assume BITMAPINFOHEADER */
302 WARN( "(%lu): unknown/wrong size for header\n", info
->biSize
);
306 dst
->biSize
= sizeof(*dst
);
308 if (!is_valid_dib_format( dst
, allow_compression
)) return FALSE
;
310 colour_table_size
= 0;
311 if (dst
->biCompression
== BI_BITFIELDS
)
313 colour_table_size
= 3 * sizeof(DWORD
);
315 else if (dst
->biBitCount
<= 8)
317 UINT elm_size
= coloruse
== DIB_PAL_COLORS
? sizeof(WORD
) : sizeof(DWORD
);
318 UINT colours
= dst
->biClrUsed
;
320 /* Windows never truncates colour tables, even if they are
321 * unnecessarily big (> 1<<bpp). We emulate this behaviour. */
323 if (colours
> UINT_MAX
/ elm_size
)
325 WARN( "too many colours in palette (%u > %u)\n",
326 colours
, UINT_MAX
/ elm_size
);
330 colour_table_size
= colours
* elm_size
;
333 *bmi_size
= sizeof(BITMAPINFOHEADER
) + colour_table_size
;
334 if (*bmi_size
< sizeof(BITMAPINFOHEADER
))
337 if (dst
->biCompression
== BI_RGB
|| dst
->biCompression
== BI_BITFIELDS
)
338 *img_size
= get_dib_stride( dst
->biWidth
, dst
->biBitCount
) * abs( dst
->biHeight
);
340 *img_size
= dst
->biSizeImage
;
345 static void emf_copy_colours_from_user_bitmapinfo( BITMAPINFO
*dst
, const BITMAPINFO
*info
, UINT coloruse
)
347 if (dst
->bmiHeader
.biCompression
== BI_BITFIELDS
)
349 /* bitfields are always at bmiColors even in larger structures */
350 memcpy( dst
->bmiColors
, info
->bmiColors
, 3 * sizeof(DWORD
) );
352 else if (dst
->bmiHeader
.biBitCount
<= 8)
354 void *src_colors
= (char *)info
+ info
->bmiHeader
.biSize
;
355 unsigned int colors
= dst
->bmiHeader
.biClrUsed
;
357 if (!colors
) colors
= 1 << dst
->bmiHeader
.biBitCount
;
359 if (coloruse
== DIB_PAL_COLORS
)
361 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(WORD
) );
363 else if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
365 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(RGBQUAD
) );
370 RGBTRIPLE
*triple
= (RGBTRIPLE
*)src_colors
;
371 for (i
= 0; i
< colors
; i
++)
373 dst
->bmiColors
[i
].rgbRed
= triple
[i
].rgbtRed
;
374 dst
->bmiColors
[i
].rgbGreen
= triple
[i
].rgbtGreen
;
375 dst
->bmiColors
[i
].rgbBlue
= triple
[i
].rgbtBlue
;
376 dst
->bmiColors
[i
].rgbReserved
= 0;
382 static UINT
emfdc_add_handle( struct emf
*emf
, HGDIOBJ obj
)
386 for (index
= 0; index
< emf
->handles_size
; index
++)
387 if (emf
->handles
[index
] == 0) break;
389 if (index
== emf
->handles_size
)
391 emf
->handles_size
+= HANDLE_LIST_INC
;
392 emf
->handles
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
394 emf
->handles_size
* sizeof(emf
->handles
[0]) );
396 emf
->handles
[index
] = obj
;
399 if (emf
->cur_handles
> emf
->emh
->nHandles
)
400 emf
->emh
->nHandles
++;
402 return index
+ 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
405 static UINT
emfdc_find_object( struct emf
*emf
, HGDIOBJ obj
)
409 for (index
= 0; index
< emf
->handles_size
; index
++)
410 if (emf
->handles
[index
] == obj
) return index
+ 1;
415 static void emfdc_delete_object( HDC hdc
, HGDIOBJ obj
)
417 DC_ATTR
*dc_attr
= get_dc_attr( hdc
);
418 struct emf
*emf
= get_dc_emf( dc_attr
);
422 if(!(index
= emfdc_find_object( emf
, obj
))) return;
424 emr
.emr
.iType
= EMR_DELETEOBJECT
;
425 emr
.emr
.nSize
= sizeof(emr
);
426 emr
.ihObject
= index
;
428 emfdc_record( emf
, &emr
.emr
);
430 emf
->handles
[index
- 1] = 0;
434 static BOOL
emfdc_add_palette_entry( struct emf
*emf
, PALETTEENTRY
*entry
)
438 for (i
= 0; i
< emf
->palette_used
; i
++)
440 if (emf
->palette
[i
].peRed
== entry
->peRed
&&
441 emf
->palette
[i
].peGreen
== entry
->peGreen
&&
442 emf
->palette
[i
].peBlue
== entry
->peBlue
) return TRUE
;
445 if (emf
->palette_size
== emf
->palette_used
)
447 if (!emf
->palette_size
)
449 emf
->palette
= HeapAlloc( GetProcessHeap(), 0,
450 8 * sizeof(*emf
->palette
) );
451 if (!emf
->palette
) return FALSE
;
452 emf
->palette_size
= 8;
456 void *new_palette
= HeapReAlloc( GetProcessHeap(), 0, emf
->palette
,
457 2 * emf
->palette_size
* sizeof(*emf
->palette
) );
458 if (!new_palette
) return FALSE
;
459 emf
->palette
= new_palette
;
460 emf
->palette_size
*= 2;
464 emf
->palette
[emf
->palette_used
++] = *entry
;
468 static DWORD
emfdc_create_brush( struct emf
*emf
, HBRUSH brush
)
473 if (!GetObjectA( brush
, sizeof(logbrush
), &logbrush
)) return 0;
475 switch (logbrush
.lbStyle
) {
480 EMRCREATEBRUSHINDIRECT emr
;
481 emr
.emr
.iType
= EMR_CREATEBRUSHINDIRECT
;
482 emr
.emr
.nSize
= sizeof(emr
);
483 emr
.ihBrush
= index
= emfdc_add_handle( emf
, brush
);
484 emr
.lb
.lbStyle
= logbrush
.lbStyle
;
485 emr
.lb
.lbColor
= logbrush
.lbColor
;
486 emr
.lb
.lbHatch
= logbrush
.lbHatch
;
488 if(!emfdc_record( emf
, &emr
.emr
))
495 EMRCREATEDIBPATTERNBRUSHPT
*emr
;
496 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
497 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
501 if (!NtGdiIcmBrushInfo( 0, brush
, info
, NULL
, NULL
, &usage
, NULL
, 0 )) break;
502 info_size
= get_dib_info_size( info
, usage
);
504 emr
= HeapAlloc( GetProcessHeap(), 0,
505 sizeof(EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
) +
506 info_size
+info
->bmiHeader
.biSizeImage
);
509 /* FIXME: There is an extra DWORD written by native before the BMI.
510 * Not sure what it's meant to contain.
512 emr
->offBmi
= sizeof( EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
);
513 *(DWORD
*)(emr
+ 1) = 0x20000000;
515 if (logbrush
.lbStyle
== BS_PATTERN
&& info
->bmiHeader
.biBitCount
== 1)
517 /* Presumably to reduce the size of the written EMF, MS supports an
518 * undocumented iUsage value of 2, indicating a mono bitmap without the
519 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
520 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
521 * irrelevant/constant for monochrome bitmaps.
522 * FIXME: It may be that the DIB functions themselves accept this value.
524 emr
->emr
.iType
= EMR_CREATEMONOBRUSH
;
525 usage
= DIB_PAL_INDICES
;
526 emr
->cbBmi
= sizeof( BITMAPINFOHEADER
);
530 emr
->emr
.iType
= EMR_CREATEDIBPATTERNBRUSHPT
;
531 emr
->cbBmi
= info_size
;
533 emr
->ihBrush
= index
= emfdc_add_handle( emf
, brush
);
535 emr
->offBits
= emr
->offBmi
+ emr
->cbBmi
;
536 emr
->cbBits
= info
->bmiHeader
.biSizeImage
;
537 emr
->emr
.nSize
= emr
->offBits
+ emr
->cbBits
;
539 if (info
->bmiHeader
.biClrUsed
== 1 << info
->bmiHeader
.biBitCount
)
540 info
->bmiHeader
.biClrUsed
= 0;
541 memcpy( (BYTE
*)emr
+ emr
->offBmi
, info
, emr
->cbBmi
);
542 NtGdiIcmBrushInfo( 0, brush
, NULL
, (char *)emr
+ emr
->offBits
, NULL
, NULL
, NULL
, 0 );
544 if (!emfdc_record( emf
, &emr
->emr
)) index
= 0;
545 HeapFree( GetProcessHeap(), 0, emr
);
550 FIXME("Unknown style %x\n", logbrush
.lbStyle
);
557 static BOOL
emfdc_select_brush( DC_ATTR
*dc_attr
, HBRUSH brush
)
559 struct emf
*emf
= get_dc_emf( dc_attr
);
564 /* If the object is a stock brush object, do not need to create it.
565 * See definitions in wingdi.h for range of stock brushes.
566 * We do however have to handle setting the higher order bit to
567 * designate that this is a stock object.
569 for (i
= WHITE_BRUSH
; i
<= DC_BRUSH
; i
++)
571 if (brush
== GetStockObject(i
))
573 index
= i
| 0x80000000;
578 if (!index
&& !(index
= emfdc_find_object( emf
, brush
)))
580 if (!(index
= emfdc_create_brush( emf
, brush
))) return 0;
581 GDI_hdc_using_object( brush
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
584 emr
.emr
.iType
= EMR_SELECTOBJECT
;
585 emr
.emr
.nSize
= sizeof(emr
);
586 emr
.ihObject
= index
;
587 return emfdc_record( emf
, &emr
.emr
);
590 static BOOL
emfdc_create_font( struct emf
*emf
, HFONT font
)
593 EMREXTCREATEFONTINDIRECTW emr
;
596 if (!GetObjectW( font
, sizeof(emr
.elfw
.elfLogFont
), &emr
.elfw
.elfLogFont
)) return FALSE
;
598 emr
.emr
.iType
= EMR_EXTCREATEFONTINDIRECTW
;
599 emr
.emr
.nSize
= (sizeof(emr
) + 3) / 4 * 4;
600 emr
.ihFont
= index
= emfdc_add_handle( emf
, font
);
601 emr
.elfw
.elfFullName
[0] = '\0';
602 emr
.elfw
.elfStyle
[0] = '\0';
603 emr
.elfw
.elfVersion
= 0;
604 emr
.elfw
.elfStyleSize
= 0;
605 emr
.elfw
.elfMatch
= 0;
606 emr
.elfw
.elfReserved
= 0;
607 for (i
= 0; i
< ELF_VENDOR_SIZE
; i
++)
608 emr
.elfw
.elfVendorId
[i
] = 0;
609 emr
.elfw
.elfCulture
= PAN_CULTURE_LATIN
;
610 emr
.elfw
.elfPanose
.bFamilyType
= PAN_NO_FIT
;
611 emr
.elfw
.elfPanose
.bSerifStyle
= PAN_NO_FIT
;
612 emr
.elfw
.elfPanose
.bWeight
= PAN_NO_FIT
;
613 emr
.elfw
.elfPanose
.bProportion
= PAN_NO_FIT
;
614 emr
.elfw
.elfPanose
.bContrast
= PAN_NO_FIT
;
615 emr
.elfw
.elfPanose
.bStrokeVariation
= PAN_NO_FIT
;
616 emr
.elfw
.elfPanose
.bArmStyle
= PAN_NO_FIT
;
617 emr
.elfw
.elfPanose
.bLetterform
= PAN_NO_FIT
;
618 emr
.elfw
.elfPanose
.bMidline
= PAN_NO_FIT
;
619 emr
.elfw
.elfPanose
.bXHeight
= PAN_NO_FIT
;
621 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
624 static BOOL
emfdc_select_font( DC_ATTR
*dc_attr
, HFONT font
)
626 struct emf
*emf
= get_dc_emf( dc_attr
);
631 /* If the object is a stock font object, do not need to create it.
632 * See definitions in wingdi.h for range of stock fonts.
633 * We do however have to handle setting the higher order bit to
634 * designate that this is a stock object.
637 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
639 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
))
641 index
= i
| 0x80000000;
646 if (!(index
= emfdc_find_object( emf
, font
)))
648 if (!(index
= emfdc_create_font( emf
, font
))) return FALSE
;
649 GDI_hdc_using_object( font
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
653 emr
.emr
.iType
= EMR_SELECTOBJECT
;
654 emr
.emr
.nSize
= sizeof(emr
);
655 emr
.ihObject
= index
;
656 return emfdc_record( emf
, &emr
.emr
);
659 static DWORD
emfdc_ext_create_pen( struct emf
*emf
, HPEN pen
)
661 EMREXTCREATEPEN
*emr
;
665 if (!(size
= GetObjectW( pen
, 0, NULL
)))
667 emr_size
= sizeof(*emr
) - sizeof(emr
->elp
) + size
;
668 emr
= HeapAlloc( GetProcessHeap(), 0, emr_size
);
671 GetObjectW( pen
, size
, &emr
->elp
);
673 if (emr
->elp
.elpBrushStyle
== BS_DIBPATTERN
||
674 emr
->elp
.elpBrushStyle
== BS_DIBPATTERNPT
||
675 emr
->elp
.elpBrushStyle
== BS_PATTERN
)
677 FIXME( "elpBrushStyle = %d\n", emr
->elp
.elpBrushStyle
);
678 HeapFree( GetProcessHeap(), 0, emr
);
681 emr
->offBmi
= emr
->cbBmi
= emr
->offBits
= emr
->cbBits
= 0;
683 emr
->emr
.iType
= EMR_EXTCREATEPEN
;
684 emr
->emr
.nSize
= emr_size
;
685 emr
->ihPen
= ret
= emfdc_add_handle( emf
, pen
);
686 ret
= emfdc_record( emf
, &emr
->emr
) ? ret
: 0;
687 HeapFree( GetProcessHeap(), 0, emr
);
691 static DWORD
emfdc_create_pen( struct emf
*emf
, HPEN hPen
)
696 if (!GetObjectW( hPen
, sizeof(emr
.lopn
), &emr
.lopn
))
697 return emfdc_ext_create_pen( emf
, hPen
);
699 emr
.emr
.iType
= EMR_CREATEPEN
;
700 emr
.emr
.nSize
= sizeof(emr
);
701 emr
.ihPen
= index
= emfdc_add_handle( emf
, hPen
);
702 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
705 static BOOL
emfdc_select_pen( DC_ATTR
*dc_attr
, HPEN pen
)
707 struct emf
*emf
= get_dc_emf( dc_attr
);
712 /* If the object is a stock pen object, do not need to create it.
713 * See definitions in wingdi.h for range of stock pens.
714 * We do however have to handle setting the higher order bit to
715 * designate that this is a stock object.
718 for (i
= WHITE_PEN
; i
<= DC_PEN
; i
++)
720 if (pen
== GetStockObject(i
))
722 index
= i
| 0x80000000;
726 if (!index
&& !(index
= emfdc_find_object( emf
, pen
)))
728 if (!(index
= emfdc_create_pen( emf
, pen
))) return FALSE
;
729 GDI_hdc_using_object( pen
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
732 emr
.emr
.iType
= EMR_SELECTOBJECT
;
733 emr
.emr
.nSize
= sizeof(emr
);
734 emr
.ihObject
= index
;
735 return emfdc_record( emf
, &emr
.emr
);
738 static DWORD
emfdc_create_palette( struct emf
*emf
, HPALETTE hPal
)
740 BYTE data
[offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[256] )];
741 EMRCREATEPALETTE
*hdr
= (EMRCREATEPALETTE
*)data
;
744 memset( data
, 0, sizeof(data
) );
746 hdr
->lgpl
.palVersion
= 0x300;
747 hdr
->lgpl
.palNumEntries
= GetPaletteEntries( hPal
, 0, 256, hdr
->lgpl
.palPalEntry
);
748 if (!hdr
->lgpl
.palNumEntries
)
751 for (i
= 0; i
< hdr
->lgpl
.palNumEntries
; i
++)
753 hdr
->lgpl
.palPalEntry
[i
].peFlags
= 0;
754 emfdc_add_palette_entry( emf
, hdr
->lgpl
.palPalEntry
+ i
);
757 hdr
->emr
.iType
= EMR_CREATEPALETTE
;
758 hdr
->emr
.nSize
= offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[hdr
->lgpl
.palNumEntries
] );
759 hdr
->ihPal
= emfdc_add_handle( emf
, hPal
);
761 if (!emfdc_record( emf
, &hdr
->emr
))
766 BOOL
EMFDC_SelectPalette( DC_ATTR
*dc_attr
, HPALETTE palette
)
768 struct emf
*emf
= get_dc_emf( dc_attr
);
769 EMRSELECTPALETTE emr
;
772 if (palette
== GetStockObject( DEFAULT_PALETTE
))
774 index
= DEFAULT_PALETTE
| 0x80000000;
776 else if (!(index
= emfdc_find_object( emf
, palette
)))
778 if (!(index
= emfdc_create_palette( emf
, palette
))) return 0;
779 GDI_hdc_using_object( palette
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
782 emr
.emr
.iType
= EMR_SELECTPALETTE
;
783 emr
.emr
.nSize
= sizeof(emr
);
785 return emfdc_record( emf
, &emr
.emr
);
788 BOOL
EMFDC_RealizePalette( DC_ATTR
*dc_attr
)
790 HPALETTE palette
= GetCurrentObject( dc_attr_handle( dc_attr
), OBJ_PAL
);
791 struct emf
*emf
= get_dc_emf( dc_attr
);
792 EMRREALIZEPALETTE emr
;
794 if (palette
== GetStockObject( DEFAULT_PALETTE
))
797 emr
.emr
.iType
= EMR_REALIZEPALETTE
;
798 emr
.emr
.nSize
= sizeof(emr
);
799 return emfdc_record( emf
, &emr
.emr
);
802 BOOL
EMFDC_SelectObject( DC_ATTR
*dc_attr
, HGDIOBJ obj
)
804 switch (gdi_handle_type( obj
))
806 case NTGDI_OBJ_BRUSH
:
807 return emfdc_select_brush( dc_attr
, obj
);
809 return emfdc_select_font( dc_attr
, obj
);
811 case NTGDI_OBJ_EXTPEN
:
812 return emfdc_select_pen( dc_attr
, obj
);
818 /* determine if we can use 16-bit points to store all the input points */
819 static BOOL
can_use_short_points( const POINT
*pts
, UINT count
)
823 for (i
= 0; i
< count
; i
++)
824 if (((pts
[i
].x
+ 0x8000) & ~0xffff) || ((pts
[i
].y
+ 0x8000) & ~0xffff))
829 /* store points in either long or short format; return a pointer to the end of the stored data */
830 static void *store_points( POINTL
*dest
, const POINT
*pts
, UINT count
, BOOL short_points
)
835 POINTS
*dest_short
= (POINTS
*)dest
;
837 for (i
= 0; i
< count
; i
++)
839 dest_short
[i
].x
= pts
[i
].x
;
840 dest_short
[i
].y
= pts
[i
].y
;
842 return dest_short
+ count
;
846 memcpy( dest
, pts
, count
* sizeof(*dest
) );
851 /* compute the bounds of an array of points, optionally including the current position */
852 static void get_points_bounds( RECTL
*bounds
, const POINT
*pts
, UINT count
, DC_ATTR
*dc_attr
)
858 bounds
->left
= bounds
->right
= dc_attr
->cur_pos
.x
;
859 bounds
->top
= bounds
->bottom
= dc_attr
->cur_pos
.y
;
863 bounds
->left
= bounds
->right
= pts
[0].x
;
864 bounds
->top
= bounds
->bottom
= pts
[0].y
;
866 else *bounds
= empty_bounds
;
868 for (i
= 0; i
< count
; i
++)
870 bounds
->left
= min( bounds
->left
, pts
[i
].x
);
871 bounds
->right
= max( bounds
->right
, pts
[i
].x
);
872 bounds
->top
= min( bounds
->top
, pts
[i
].y
);
873 bounds
->bottom
= max( bounds
->bottom
, pts
[i
].y
);
877 /* helper for path stroke and fill functions */
878 static BOOL
emfdrv_stroke_and_fill_path( struct emf
*emf
, INT type
)
880 EMRSTROKEANDFILLPATH emr
;
883 emr
.emr
.iType
= type
;
884 emr
.emr
.nSize
= sizeof(emr
);
885 emr
.rclBounds
= empty_bounds
;
887 if ((region
= NtGdiPathToRegion( dc_attr_handle( emf
->dc_attr
))))
889 NtGdiGetRgnBox( region
, (RECT
*)&emr
.rclBounds
);
890 DeleteObject( region
);
893 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
894 if (!region
) return FALSE
;
895 emfdc_update_bounds( emf
, &emr
.rclBounds
);
899 BOOL
EMFDC_MoveTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
901 struct emf
*emf
= get_dc_emf( dc_attr
);
904 emr
.emr
.iType
= EMR_MOVETOEX
;
905 emr
.emr
.nSize
= sizeof(emr
);
908 return emfdc_record( emf
, &emr
.emr
);
911 BOOL
EMFDC_LineTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
915 emr
.emr
.iType
= EMR_LINETO
;
916 emr
.emr
.nSize
= sizeof(emr
);
919 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
922 BOOL
EMFDC_ArcChordPie( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
,
923 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD type
)
925 struct emf
*emf
= get_dc_emf( dc_attr
);
929 if (left
== right
|| top
== bottom
) return FALSE
;
931 if (left
> right
) { temp
= left
; left
= right
; right
= temp
; }
932 if (top
> bottom
) { temp
= top
; top
= bottom
; bottom
= temp
; }
934 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
940 emr
.emr
.iType
= type
;
941 emr
.emr
.nSize
= sizeof(emr
);
942 emr
.rclBox
.left
= left
;
943 emr
.rclBox
.top
= top
;
944 emr
.rclBox
.right
= right
;
945 emr
.rclBox
.bottom
= bottom
;
946 emr
.ptlStart
.x
= xstart
;
947 emr
.ptlStart
.y
= ystart
;
950 return emfdc_record( emf
, &emr
.emr
);
953 BOOL
EMFDC_AngleArc( DC_ATTR
*dc_attr
, INT x
, INT y
, DWORD radius
, FLOAT start
, FLOAT sweep
)
957 emr
.emr
.iType
= EMR_ANGLEARC
;
958 emr
.emr
.nSize
= sizeof( emr
);
961 emr
.nRadius
= radius
;
962 emr
.eStartAngle
= start
;
963 emr
.eSweepAngle
= sweep
;
964 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
967 BOOL
EMFDC_Ellipse( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
969 struct emf
*emf
= get_dc_emf( dc_attr
);
972 if (left
== right
|| top
== bottom
) return FALSE
;
974 emr
.emr
.iType
= EMR_ELLIPSE
;
975 emr
.emr
.nSize
= sizeof(emr
);
976 emr
.rclBox
.left
= min( left
, right
);
977 emr
.rclBox
.top
= min( top
, bottom
);
978 emr
.rclBox
.right
= max( left
, right
);
979 emr
.rclBox
.bottom
= max( top
, bottom
);
980 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
985 return emfdc_record( emf
, &emr
.emr
);
988 BOOL
EMFDC_Rectangle( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
990 struct emf
*emf
= get_dc_emf( dc_attr
);
993 if(left
== right
|| top
== bottom
) return FALSE
;
995 emr
.emr
.iType
= EMR_RECTANGLE
;
996 emr
.emr
.nSize
= sizeof(emr
);
997 emr
.rclBox
.left
= min( left
, right
);
998 emr
.rclBox
.top
= min( top
, bottom
);
999 emr
.rclBox
.right
= max( left
, right
);
1000 emr
.rclBox
.bottom
= max( top
, bottom
);
1001 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1004 emr
.rclBox
.bottom
--;
1006 return emfdc_record( emf
, &emr
.emr
);
1009 BOOL
EMFDC_RoundRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
,
1010 INT bottom
, INT ell_width
, INT ell_height
)
1012 struct emf
*emf
= get_dc_emf( dc_attr
);
1015 if (left
== right
|| top
== bottom
) return FALSE
;
1017 emr
.emr
.iType
= EMR_ROUNDRECT
;
1018 emr
.emr
.nSize
= sizeof(emr
);
1019 emr
.rclBox
.left
= min( left
, right
);
1020 emr
.rclBox
.top
= min( top
, bottom
);
1021 emr
.rclBox
.right
= max( left
, right
);
1022 emr
.rclBox
.bottom
= max( top
, bottom
);
1023 emr
.szlCorner
.cx
= ell_width
;
1024 emr
.szlCorner
.cy
= ell_height
;
1025 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1028 emr
.rclBox
.bottom
--;
1030 return emfdc_record( emf
, &emr
.emr
);
1033 BOOL
EMFDC_SetPixel( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
)
1037 emr
.emr
.iType
= EMR_SETPIXELV
;
1038 emr
.emr
.nSize
= sizeof(emr
);
1041 emr
.crColor
= color
;
1042 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
1045 static BOOL
emfdc_polylinegon( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
, DWORD type
)
1047 struct emf
*emf
= get_dc_emf( dc_attr
);
1050 BOOL ret
, use_small_emr
= can_use_short_points( points
, count
);
1052 size
= use_small_emr
? offsetof( EMRPOLYLINE16
, apts
[count
] ) : offsetof( EMRPOLYLINE
, aptl
[count
] );
1054 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1055 emr
->emr
.iType
= use_small_emr
? type
+ EMR_POLYLINE16
- EMR_POLYLINE
: type
;
1056 emr
->emr
.nSize
= size
;
1059 store_points( emr
->aptl
, points
, count
, use_small_emr
);
1062 get_points_bounds( &emr
->rclBounds
, points
, count
,
1063 (type
== EMR_POLYBEZIERTO
|| type
== EMR_POLYLINETO
) ? dc_attr
: 0 );
1065 emr
->rclBounds
= empty_bounds
;
1067 ret
= emfdc_record( emf
, &emr
->emr
);
1068 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1069 HeapFree( GetProcessHeap(), 0, emr
);
1073 BOOL
EMFDC_Polyline( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1075 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINE
);
1078 BOOL
EMFDC_PolylineTo( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1080 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINETO
);
1083 BOOL
EMFDC_Polygon( DC_ATTR
*dc_attr
, const POINT
*pt
, INT count
)
1085 if(count
< 2) return FALSE
;
1086 return emfdc_polylinegon( dc_attr
, pt
, count
, EMR_POLYGON
);
1089 BOOL
EMFDC_PolyBezier( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1091 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIER
);
1094 BOOL
EMFDC_PolyBezierTo( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1096 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIERTO
);
1099 static BOOL
emfdc_poly_polylinegon( struct emf
*emf
, const POINT
*pt
, const INT
*counts
,
1100 UINT polys
, DWORD type
)
1102 EMRPOLYPOLYLINE
*emr
;
1103 DWORD cptl
= 0, poly
, size
;
1104 BOOL ret
, use_small_emr
, bounds_valid
= TRUE
;
1106 for(poly
= 0; poly
< polys
; poly
++) {
1107 cptl
+= counts
[poly
];
1108 if(counts
[poly
] < 2) bounds_valid
= FALSE
;
1110 if(!cptl
) bounds_valid
= FALSE
;
1111 use_small_emr
= can_use_short_points( pt
, cptl
);
1113 size
= FIELD_OFFSET(EMRPOLYPOLYLINE
, aPolyCounts
[polys
]);
1115 size
+= cptl
* sizeof(POINTS
);
1117 size
+= cptl
* sizeof(POINTL
);
1119 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1121 emr
->emr
.iType
= type
;
1122 if(use_small_emr
) emr
->emr
.iType
+= EMR_POLYPOLYLINE16
- EMR_POLYPOLYLINE
;
1124 emr
->emr
.nSize
= size
;
1125 if(bounds_valid
&& !emf
->path
)
1126 get_points_bounds( &emr
->rclBounds
, pt
, cptl
, 0 );
1128 emr
->rclBounds
= empty_bounds
;
1129 emr
->nPolys
= polys
;
1134 memcpy( emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
) );
1135 store_points( (POINTL
*)(emr
->aPolyCounts
+ polys
), pt
, cptl
, use_small_emr
);
1138 ret
= emfdc_record( emf
, &emr
->emr
);
1139 if(ret
&& !bounds_valid
)
1142 SetLastError( ERROR_INVALID_PARAMETER
);
1144 if(ret
&& !emf
->path
)
1145 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1146 HeapFree( GetProcessHeap(), 0, emr
);
1150 BOOL
EMFDC_PolyPolyline( DC_ATTR
*dc_attr
, const POINT
*pt
, const DWORD
*counts
, DWORD polys
)
1152 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, (const INT
*)counts
, polys
, EMR_POLYPOLYLINE
);
1155 BOOL
EMFDC_PolyPolygon( DC_ATTR
*dc_attr
, const POINT
*pt
, const INT
*counts
, UINT polys
)
1157 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, counts
, polys
, EMR_POLYPOLYGON
);
1160 BOOL
EMFDC_PolyDraw( DC_ATTR
*dc_attr
, const POINT
*pts
, const BYTE
*types
, DWORD count
)
1162 struct emf
*emf
= get_dc_emf( dc_attr
);
1166 BOOL use_small_emr
= can_use_short_points( pts
, count
);
1169 size
= use_small_emr
? offsetof( EMRPOLYDRAW16
, apts
[count
] )
1170 : offsetof( EMRPOLYDRAW
, aptl
[count
] );
1171 size
+= aligned_size(count
);
1173 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1175 emr
->emr
.iType
= use_small_emr
? EMR_POLYDRAW16
: EMR_POLYDRAW
;
1176 emr
->emr
.nSize
= size
;
1179 types_dest
= store_points( emr
->aptl
, pts
, count
, use_small_emr
);
1180 memcpy( types_dest
, types
, count
);
1181 pad_record( types_dest
, count
);
1184 get_points_bounds( &emr
->rclBounds
, pts
, count
, 0 );
1186 emr
->rclBounds
= empty_bounds
;
1188 ret
= emfdc_record( emf
, &emr
->emr
);
1189 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1190 HeapFree( GetProcessHeap(), 0, emr
);
1194 INT
EMFDC_ExtEscape( DC_ATTR
*dc_attr
, INT escape
, INT input_size
, const char *input
,
1195 INT output_size
, char *output
)
1200 if (escape
== QUERYESCSUPPORT
) return 0;
1202 size
= aligned_size(FIELD_OFFSET( EMREXTESCAPE
, EscData
[input_size
] ));
1203 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return 0;
1205 emr
->emr
.iType
= EMR_EXTESCAPE
;
1206 emr
->emr
.nSize
= size
;
1207 emr
->iEscape
= escape
;
1208 emr
->cbEscData
= input_size
;
1209 memcpy(emr
->EscData
, input
, input_size
);
1210 pad_record(emr
->EscData
, input_size
);
1211 emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1212 HeapFree( GetProcessHeap(), 0, emr
);
1213 if (output_size
&& output
) return 0;
1215 if (escape
== PASSTHROUGH
|| escape
== POSTSCRIPT_PASSTHROUGH
)
1216 input_size
-= sizeof(WORD
);
1217 return input_size
? input_size
: 1;
1220 BOOL
EMFDC_ExtFloodFill( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
, UINT fill_type
)
1222 EMREXTFLOODFILL emr
;
1224 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
1225 emr
.emr
.nSize
= sizeof(emr
);
1228 emr
.crColor
= color
;
1229 emr
.iMode
= fill_type
;
1230 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
1233 BOOL
EMFDC_FillRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
)
1235 struct emf
*emf
= get_dc_emf( dc_attr
);
1237 DWORD size
, rgnsize
, index
;
1240 if (!(index
= emfdc_create_brush( emf
, hbrush
))) return FALSE
;
1242 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1243 size
= rgnsize
+ offsetof(EMRFILLRGN
,RgnData
);
1244 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1246 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1248 emr
->emr
.iType
= EMR_FILLRGN
;
1249 emr
->emr
.nSize
= size
;
1250 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1251 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1252 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1253 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1254 emr
->cbRgnData
= rgnsize
;
1255 emr
->ihBrush
= index
;
1257 ret
= emfdc_record( emf
, &emr
->emr
);
1258 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1259 HeapFree( GetProcessHeap(), 0, emr
);
1263 BOOL
EMFDC_FrameRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
1265 struct emf
*emf
= get_dc_emf( dc_attr
);
1267 DWORD size
, rgnsize
, index
;
1270 index
= emfdc_create_brush( emf
, hbrush
);
1271 if(!index
) return FALSE
;
1273 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1274 size
= rgnsize
+ offsetof(EMRFRAMERGN
,RgnData
);
1275 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1277 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1279 emr
->emr
.iType
= EMR_FRAMERGN
;
1280 emr
->emr
.nSize
= size
;
1281 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1282 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1283 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1284 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1285 emr
->cbRgnData
= rgnsize
;
1286 emr
->ihBrush
= index
;
1287 emr
->szlStroke
.cx
= width
;
1288 emr
->szlStroke
.cy
= height
;
1290 ret
= emfdc_record( emf
, &emr
->emr
);
1291 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1292 HeapFree( GetProcessHeap(), 0, emr
);
1296 static BOOL
emfdc_paint_invert_region( struct emf
*emf
, HRGN hrgn
, DWORD iType
)
1299 DWORD size
, rgnsize
;
1302 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1303 size
= rgnsize
+ offsetof(EMRINVERTRGN
,RgnData
);
1304 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1306 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1308 emr
->emr
.iType
= iType
;
1309 emr
->emr
.nSize
= size
;
1310 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1311 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1312 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1313 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1314 emr
->cbRgnData
= rgnsize
;
1316 ret
= emfdc_record( emf
, &emr
->emr
);
1317 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1318 HeapFree( GetProcessHeap(), 0, emr
);
1322 BOOL
EMFDC_PaintRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1324 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_PAINTRGN
);
1327 BOOL
EMFDC_InvertRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1329 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_INVERTRGN
);
1332 BOOL
EMFDC_ExtTextOut( DC_ATTR
*dc_attr
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1333 const WCHAR
*str
, UINT count
, const INT
*dx
)
1335 struct emf
*emf
= get_dc_emf( dc_attr
);
1336 HDC hdc
= dc_attr_handle( dc_attr
);
1337 FLOAT ex_scale
, ey_scale
;
1338 EMREXTTEXTOUTW
*emr
;
1339 int text_height
= 0, top
= y
, bottom
= y
;
1345 if (!dx
&& flags
& ETO_PDY
) return FALSE
;
1346 dx_len
= flags
& ETO_PDY
? count
* 2 : count
;
1347 size
= sizeof(*emr
) + ((count
+1) & ~1) * sizeof(WCHAR
) + dx_len
* sizeof(INT
);
1349 TRACE( "%s %s count %d size = %ld\n", debugstr_wn(str
, count
),
1350 wine_dbgstr_rect(rect
), count
, size
);
1351 emr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1353 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1355 HDC hdc
= dc_attr_handle( dc_attr
);
1356 const INT horzSize
= GetDeviceCaps( hdc
, HORZSIZE
);
1357 const INT horzRes
= GetDeviceCaps( hdc
, HORZRES
);
1358 const INT vertSize
= GetDeviceCaps( hdc
, VERTSIZE
);
1359 const INT vertRes
= GetDeviceCaps( hdc
, VERTRES
);
1360 SIZE wndext
, vportext
;
1362 GetViewportExtEx( hdc
, &vportext
);
1363 GetWindowExtEx( hdc
, &wndext
);
1364 ex_scale
= 100.0 * ((FLOAT
)horzSize
/ (FLOAT
)horzRes
) /
1365 ((FLOAT
)wndext
.cx
/ (FLOAT
)vportext
.cx
);
1366 ey_scale
= 100.0 * ((FLOAT
)vertSize
/ (FLOAT
)vertRes
) /
1367 ((FLOAT
)wndext
.cy
/ (FLOAT
)vportext
.cy
);
1375 emr
->emr
.iType
= EMR_EXTTEXTOUTW
;
1376 emr
->emr
.nSize
= size
;
1377 emr
->iGraphicsMode
= dc_attr
->graphics_mode
;
1378 emr
->exScale
= ex_scale
;
1379 emr
->eyScale
= ey_scale
;
1380 emr
->emrtext
.ptlReference
.x
= x
;
1381 emr
->emrtext
.ptlReference
.y
= y
;
1382 emr
->emrtext
.nChars
= count
;
1383 emr
->emrtext
.offString
= sizeof(*emr
);
1384 memcpy( (char*)emr
+ emr
->emrtext
.offString
, str
, count
* sizeof(WCHAR
) );
1385 emr
->emrtext
.fOptions
= flags
;
1388 emr
->emrtext
.rcl
.left
= emr
->emrtext
.rcl
.top
= 0;
1389 emr
->emrtext
.rcl
.right
= emr
->emrtext
.rcl
.bottom
= -1;
1393 emr
->emrtext
.rcl
.left
= rect
->left
;
1394 emr
->emrtext
.rcl
.top
= rect
->top
;
1395 emr
->emrtext
.rcl
.right
= rect
->right
;
1396 emr
->emrtext
.rcl
.bottom
= rect
->bottom
;
1399 emr
->emrtext
.offDx
= emr
->emrtext
.offString
+ ((count
+1) & ~1) * sizeof(WCHAR
);
1404 memcpy( (char*)emr
+ emr
->emrtext
.offDx
, dx
, dx_len
* sizeof(INT
) );
1405 if (GetTextExtentPoint32W( hdc
, str
, count
, &str_size
))
1406 text_height
= str_size
.cy
;
1407 if (flags
& ETO_PDY
)
1410 for (i
= 0; i
< count
; i
++)
1412 top
= min( top
, cur_y
);
1413 bottom
= max( bottom
, cur_y
);
1414 text_width
+= dx
[2 * i
];
1415 cur_y
-= dx
[2 * i
+ 1];
1420 for (i
= 0; i
< count
; i
++) text_width
+= dx
[i
];
1426 INT
*emf_dx
= (INT
*)((char*)emr
+ emr
->emrtext
.offDx
);
1428 for (i
= 0; i
< count
; i
++)
1430 if (GetTextExtentPoint32W( hdc
, str
+ i
, 1, &charSize
))
1432 emf_dx
[i
] = charSize
.cx
;
1433 text_width
+= charSize
.cx
;
1434 text_height
= max( text_height
, charSize
.cy
);
1441 emr
->rclBounds
.left
= emr
->rclBounds
.top
= 0;
1442 emr
->rclBounds
.right
= emr
->rclBounds
.bottom
= -1;
1446 /* FIXME: handle font escapement */
1447 switch (dc_attr
->text_align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1450 emr
->rclBounds
.left
= x
- (text_width
/ 2) - 1;
1451 emr
->rclBounds
.right
= x
+ (text_width
/ 2) + 1;
1455 emr
->rclBounds
.left
= x
- text_width
- 1;
1456 emr
->rclBounds
.right
= x
;
1459 default: /* TA_LEFT */
1460 emr
->rclBounds
.left
= x
;
1461 emr
->rclBounds
.right
= x
+ text_width
+ 1;
1464 switch (dc_attr
->text_align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1467 if (!GetTextMetricsW( hdc
, &tm
)) tm
.tmDescent
= 0;
1468 /* Play safe here... it's better to have a bounding box */
1469 /* that is too big than too small. */
1470 emr
->rclBounds
.top
= top
- text_height
- 1;
1471 emr
->rclBounds
.bottom
= bottom
+ tm
.tmDescent
+ 1;
1475 emr
->rclBounds
.top
= top
- text_height
- 1;
1476 emr
->rclBounds
.bottom
= bottom
;
1479 default: /* TA_TOP */
1480 emr
->rclBounds
.top
= top
;
1481 emr
->rclBounds
.bottom
= bottom
+ text_height
+ 1;
1483 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1486 ret
= emfdc_record( emf
, &emr
->emr
);
1487 HeapFree( GetProcessHeap(), 0, emr
);
1491 BOOL
EMFDC_GradientFill( DC_ATTR
*dc_attr
, TRIVERTEX
*vert_array
, ULONG nvert
,
1492 void *grad_array
, ULONG ngrad
, ULONG mode
)
1494 EMRGRADIENTFILL
*emr
;
1495 ULONG i
, pt
, size
, num_pts
= ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2);
1496 const ULONG
*pts
= (const ULONG
*)grad_array
;
1499 size
= FIELD_OFFSET(EMRGRADIENTFILL
, Ver
[nvert
]) + num_pts
* sizeof(pts
[0]);
1501 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1502 if (!emr
) return FALSE
;
1504 for (i
= 0; i
< num_pts
; i
++)
1510 emr
->rclBounds
.left
= emr
->rclBounds
.right
= vert_array
[pt
].x
;
1511 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1515 if (vert_array
[pt
].x
< emr
->rclBounds
.left
)
1516 emr
->rclBounds
.left
= vert_array
[pt
].x
;
1517 else if (vert_array
[pt
].x
> emr
->rclBounds
.right
)
1518 emr
->rclBounds
.right
= vert_array
[pt
].x
;
1519 if (vert_array
[pt
].y
< emr
->rclBounds
.top
)
1520 emr
->rclBounds
.top
= vert_array
[pt
].y
;
1521 else if (vert_array
[pt
].y
> emr
->rclBounds
.bottom
)
1522 emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1525 emr
->rclBounds
.right
--;
1526 emr
->rclBounds
.bottom
--;
1528 emr
->emr
.iType
= EMR_GRADIENTFILL
;
1529 emr
->emr
.nSize
= size
;
1533 memcpy( emr
->Ver
, vert_array
, nvert
* sizeof(vert_array
[0]) );
1534 memcpy( emr
->Ver
+ nvert
, pts
, num_pts
* sizeof(pts
[0]) );
1536 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1537 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1538 HeapFree( GetProcessHeap(), 0, emr
);
1542 BOOL
EMFDC_FillPath( DC_ATTR
*dc_attr
)
1544 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_FILLPATH
);
1547 BOOL
EMFDC_StrokeAndFillPath( DC_ATTR
*dc_attr
)
1549 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEANDFILLPATH
);
1552 BOOL
EMFDC_StrokePath( DC_ATTR
*dc_attr
)
1554 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEPATH
);
1557 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1558 static BOOL
emfdrv_stretchblt( struct emf
*emf
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1559 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1560 DWORD rop
, DWORD type
)
1562 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1563 UINT bmi_size
, emr_size
, size
;
1564 HBITMAP bitmap
, blit_bitmap
= NULL
;
1565 EMRBITBLT
*emr
= NULL
;
1570 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1573 blit_bitmap
= bitmap
;
1574 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1576 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1577 emr_size
= type
== EMR_BITBLT
? sizeof(EMRBITBLT
) : sizeof(EMRSTRETCHBLT
);
1578 size
= emr_size
+ bmi_size
+ src_info
.bmiHeader
.biSizeImage
;
1580 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1582 emr
->emr
.iType
= type
;
1583 emr
->emr
.nSize
= size
;
1584 emr
->rclBounds
.left
= x_dst
;
1585 emr
->rclBounds
.top
= y_dst
;
1586 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1587 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1590 emr
->cxDest
= width_dst
;
1591 emr
->cyDest
= height_dst
;
1594 if (type
!= EMR_BITBLT
)
1596 EMRSTRETCHBLT
*emr_stretchblt
= (EMRSTRETCHBLT
*)emr
;
1597 emr_stretchblt
->cxSrc
= width_src
;
1598 emr_stretchblt
->cySrc
= height_src
;
1601 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1602 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1603 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1604 emr
->offBmiSrc
= emr_size
;
1605 emr
->cbBmiSrc
= bmi_size
;
1606 emr
->offBitsSrc
= emr_size
+ bmi_size
;
1607 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1609 bmi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1610 bmi
->bmiHeader
= src_info
.bmiHeader
;
1611 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1612 (BYTE
*)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1615 ret
= emfdc_record( emf
, (EMR
*)emr
);
1616 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1620 HeapFree( GetProcessHeap(), 0, emr
);
1621 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1622 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1626 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1627 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1628 BLENDFUNCTION blend_function
)
1630 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
,
1631 x_src
, y_src
, width_src
, height_src
, *(DWORD
*)&blend_function
,
1635 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1637 struct emf
*emf
= get_dc_emf( dc_attr
);
1641 emr
.emr
.iType
= EMR_BITBLT
;
1642 emr
.emr
.nSize
= sizeof(emr
);
1643 emr
.rclBounds
.left
= left
;
1644 emr
.rclBounds
.top
= top
;
1645 emr
.rclBounds
.right
= left
+ width
- 1;
1646 emr
.rclBounds
.bottom
= top
+ height
- 1;
1650 emr
.cyDest
= height
;
1654 emr
.xformSrc
.eM11
= 1.0;
1655 emr
.xformSrc
.eM12
= 0.0;
1656 emr
.xformSrc
.eM21
= 0.0;
1657 emr
.xformSrc
.eM22
= 1.0;
1658 emr
.xformSrc
.eDx
= 0.0;
1659 emr
.xformSrc
.eDy
= 0.0;
1660 emr
.crBkColorSrc
= 0;
1667 ret
= emfdc_record( emf
, &emr
.emr
);
1668 if (ret
) emfdc_update_bounds( emf
, &emr
.rclBounds
);
1672 static inline BOOL
rop_uses_src( DWORD rop
)
1674 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
1677 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
1678 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
1680 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
1681 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width
, height
,
1682 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
1685 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1686 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1689 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1690 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1691 hdc_src
, x_src
, y_src
, width_src
,
1692 height_src
, rop
, EMR_STRETCHBLT
);
1695 BOOL
EMFDC_TransparentBlt( DC_ATTR
*dc_attr
, int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1696 HDC hdc_src
, int x_src
, int y_src
, int width_src
, int height_src
,
1699 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1700 hdc_src
, x_src
, y_src
, width_src
,
1701 height_src
, color
, EMR_TRANSPARENTBLT
);
1704 BOOL
EMFDC_MaskBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1705 HDC hdc_src
, INT x_src
, INT y_src
, HBITMAP mask
,
1706 INT x_mask
, INT y_mask
, DWORD rop
)
1708 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1709 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1710 struct emf
*emf
= get_dc_emf( dc_attr
);
1711 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1712 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1713 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1714 UINT bmi_size
, size
, mask_info_size
= 0;
1715 EMRMASKBLT
*emr
= NULL
;
1717 HDC blit_dc
, mask_dc
= NULL
;
1720 if (!rop_uses_src( rop
))
1721 return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1723 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1725 blit_bitmap
= bitmap
;
1726 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1732 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1733 if (mask_info
.bmiHeader
.biBitCount
== 1)
1734 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1736 else mask_info
.bmiHeader
.biSizeImage
= 0;
1738 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1739 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1741 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1743 emr
->emr
.iType
= EMR_MASKBLT
;
1744 emr
->emr
.nSize
= size
;
1745 emr
->rclBounds
.left
= x_dst
;
1746 emr
->rclBounds
.top
= y_dst
;
1747 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1748 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1751 emr
->cxDest
= width_dst
;
1752 emr
->cyDest
= height_dst
;
1756 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1757 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1758 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1759 emr
->offBmiSrc
= sizeof(*emr
);
1760 emr
->cbBmiSrc
= bmi_size
;
1761 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1762 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1763 emr
->xMask
= x_mask
;
1764 emr
->yMask
= y_mask
;
1765 emr
->iUsageMask
= DIB_PAL_INDICES
;
1766 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1767 emr
->cbBmiMask
= mask_info_size
;
1768 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1769 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1771 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1772 bmi
->bmiHeader
= src_info
.bmiHeader
;
1773 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1774 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1779 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1780 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1781 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1782 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1787 ret
= emfdc_record( emf
, (EMR
*)emr
);
1788 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1792 HeapFree( GetProcessHeap(), 0, emr
);
1793 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1794 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1795 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1796 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1800 BOOL
EMFDC_PlgBlt( DC_ATTR
*dc_attr
, const POINT
*points
, HDC hdc_src
, INT x_src
, INT y_src
,
1801 INT width
, INT height
, HBITMAP mask
, INT x_mask
, INT y_mask
)
1803 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1804 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1805 struct emf
*emf
= get_dc_emf( dc_attr
);
1806 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1807 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1808 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1809 UINT bmi_size
, size
, mask_info_size
= 0;
1810 EMRPLGBLT
*emr
= NULL
;
1812 HDC blit_dc
, mask_dc
= NULL
;
1813 int x_min
, y_min
, x_max
, y_max
, i
;
1816 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1819 blit_bitmap
= bitmap
;
1820 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1826 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1827 if (mask_info
.bmiHeader
.biBitCount
== 1)
1828 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1830 else mask_info
.bmiHeader
.biSizeImage
= 0;
1832 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1833 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1835 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1837 emr
->emr
.iType
= EMR_PLGBLT
;
1838 emr
->emr
.nSize
= size
;
1840 /* FIXME: not exactly what native does */
1841 x_min
= x_max
= points
[1].x
+ points
[2].x
- points
[0].x
;
1842 y_min
= y_max
= points
[1].y
+ points
[2].y
- points
[0].y
;
1843 for (i
= 0; i
< ARRAYSIZE(emr
->aptlDest
); i
++)
1845 x_min
= min( x_min
, points
[i
].x
);
1846 y_min
= min( y_min
, points
[i
].y
);
1847 x_max
= max( x_max
, points
[i
].x
);
1848 y_max
= max( y_min
, points
[i
].y
);
1850 emr
->rclBounds
.left
= x_min
;
1851 emr
->rclBounds
.top
= y_min
;
1852 emr
->rclBounds
.right
= x_max
;
1853 emr
->rclBounds
.bottom
= y_max
;
1854 memcpy( emr
->aptlDest
, points
, sizeof(emr
->aptlDest
) );
1858 emr
->cySrc
= height
;
1859 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1860 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1861 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1862 emr
->offBmiSrc
= sizeof(*emr
);
1863 emr
->cbBmiSrc
= bmi_size
;
1864 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1865 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1866 emr
->xMask
= x_mask
;
1867 emr
->yMask
= y_mask
;
1868 emr
->iUsageMask
= DIB_PAL_INDICES
;
1869 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1870 emr
->cbBmiMask
= mask_info_size
;
1871 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1872 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1874 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1875 bmi
->bmiHeader
= src_info
.bmiHeader
;
1876 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1877 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1882 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1883 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1884 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1885 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1890 ret
= emfdc_record( emf
, (EMR
*)emr
);
1891 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1895 HeapFree( GetProcessHeap(), 0, emr
);
1896 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1897 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1898 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1899 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1903 BOOL
EMFDC_StretchDIBits( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1904 INT x_src
, INT y_src
, INT width_src
, INT height_src
, const void *bits
,
1905 const BITMAPINFO
*info
, UINT usage
, DWORD rop
)
1907 EMRSTRETCHDIBITS
*emr
;
1909 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1910 BITMAPINFOHEADER bih
;
1914 /* calculate the size of the colour table and the image */
1915 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1916 &bmi_size
, &img_size
)) return 0;
1918 /* check for overflows */
1919 payload_size
= aligned_size(bmi_size
) + aligned_size(img_size
);
1920 if (payload_size
< bmi_size
) return 0;
1922 emr_size
= sizeof (EMRSTRETCHDIBITS
) + payload_size
;
1923 if (emr_size
< sizeof (EMRSTRETCHDIBITS
)) return 0;
1925 /* allocate record */
1926 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
))) return 0;
1928 /* fill in the EMR header at the front of our piece of memory */
1929 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
1930 emr
->emr
.nSize
= emr_size
;
1934 emr
->cxDest
= width_dst
;
1935 emr
->cyDest
= height_dst
;
1940 emr
->iUsageSrc
= usage
;
1941 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
1942 emr
->cbBmiSrc
= bmi_size
;
1943 emr
->offBitsSrc
= emr
->offBmiSrc
+ aligned_size(bmi_size
);
1944 emr
->cbBitsSrc
= img_size
;
1946 emr
->cxSrc
= width_src
;
1947 emr
->cySrc
= height_src
;
1949 emr
->rclBounds
.left
= x_dst
;
1950 emr
->rclBounds
.top
= y_dst
;
1951 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1952 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1954 /* write a bitmap info header (with colours) to the record */
1955 bi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1956 bi
->bmiHeader
= bih
;
1957 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1958 pad_record( bi
, emr
->cbBmiSrc
);
1960 /* write bitmap bits to the record */
1961 ptr
= memcpy ( (BYTE
*)emr
+ emr
->offBitsSrc
, bits
, img_size
);
1962 pad_record( ptr
, emr
->cbBitsSrc
);
1964 /* save the record we just created */
1965 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1966 if (ret
) emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1967 HeapFree( GetProcessHeap(), 0, emr
);
1971 BOOL
EMFDC_SetDIBitsToDevice( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, DWORD width
, DWORD height
,
1972 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
1973 const void *bits
, const BITMAPINFO
*info
, UINT usage
)
1975 EMRSETDIBITSTODEVICE
*emr
;
1977 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1978 UINT src_height
, stride
;
1979 BITMAPINFOHEADER bih
;
1983 /* calculate the size of the colour table and the image */
1984 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1985 &bmi_size
, &img_size
)) return 0;
1987 if (bih
.biHeight
>= 0)
1989 src_height
= (UINT
)bih
.biHeight
;
1990 if (src_height
> y_src
+ height
) src_height
= y_src
+ height
;
1992 if (src_height
< startscan
) lines
= 0;
1993 else if (lines
> src_height
- startscan
) lines
= src_height
- startscan
;
1995 if (!lines
) return 0;
1997 if (bih
.biCompression
== BI_RGB
|| bih
.biCompression
== BI_BITFIELDS
)
1999 /* truncate image and check for overflows */
2000 stride
= get_dib_stride( bih
.biWidth
, bih
.biBitCount
);
2001 img_size
= lines
* stride
;
2002 if (img_size
/ stride
!= lines
) return 0;
2006 /* check for overflows */
2007 payload_size
= aligned_size(bmi_size
) + aligned_size(img_size
);
2008 if (payload_size
< bmi_size
) return 0;
2010 emr_size
= sizeof (EMRSETDIBITSTODEVICE
) + payload_size
;
2011 if (emr_size
< sizeof (EMRSETDIBITSTODEVICE
)) return 0;
2013 /* allocate record */
2014 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, emr_size
))) return FALSE
;
2016 emr
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
2017 emr
->emr
.nSize
= emr_size
;
2018 emr
->rclBounds
.left
= x_dst
;
2019 emr
->rclBounds
.top
= y_dst
;
2020 emr
->rclBounds
.right
= x_dst
+ width
- 1;
2021 emr
->rclBounds
.bottom
= y_dst
+ height
- 1;
2027 emr
->cySrc
= height
;
2028 emr
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
2029 emr
->cbBmiSrc
= bmi_size
;
2030 emr
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + aligned_size(bmi_size
);
2031 emr
->cbBitsSrc
= img_size
;
2032 emr
->iUsageSrc
= usage
;
2033 emr
->iStartScan
= startscan
;
2034 emr
->cScans
= lines
;
2036 /* write a bitmap info header (with colours) to the record */
2037 bi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
2038 bi
->bmiHeader
= bih
;
2039 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
2040 pad_record( bi
, bmi_size
);
2042 /* write bitmap bits to the record */
2043 ptr
= memcpy ( (BYTE
*)emr
+ emr
->offBitsSrc
, bits
, img_size
);
2044 pad_record( ptr
, img_size
);
2046 if ((ret
= emfdc_record( get_dc_emf( dc_attr
), (EMR
*)emr
)))
2047 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
2049 HeapFree( GetProcessHeap(), 0, emr
);
2053 BOOL
EMFDC_SetDCBrushColor( DC_ATTR
*dc_attr
, COLORREF color
)
2055 struct emf
*emf
= get_dc_emf( dc_attr
);
2056 HDC hdc
= dc_attr_handle( dc_attr
);
2057 EMRSELECTOBJECT emr
;
2060 if (GetCurrentObject( hdc
, OBJ_BRUSH
) != GetStockObject( DC_BRUSH
)) return TRUE
;
2062 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2063 if (!(emf
->dc_brush
= CreateSolidBrush( color
))) return FALSE
;
2064 if (!(index
= emfdc_create_brush( emf
, emf
->dc_brush
))) return FALSE
;
2065 GDI_hdc_using_object( emf
->dc_brush
, hdc
, emfdc_delete_object
);
2066 emr
.emr
.iType
= EMR_SELECTOBJECT
;
2067 emr
.emr
.nSize
= sizeof(emr
);
2068 emr
.ihObject
= index
;
2069 return emfdc_record( emf
, &emr
.emr
);
2072 BOOL
EMFDC_SetDCPenColor( DC_ATTR
*dc_attr
, COLORREF color
)
2074 struct emf
*emf
= get_dc_emf( dc_attr
);
2075 HDC hdc
= dc_attr_handle( dc_attr
);
2076 EMRSELECTOBJECT emr
;
2078 LOGPEN logpen
= { PS_SOLID
, { 0, 0 }, color
};
2080 if (GetCurrentObject( hdc
, OBJ_PEN
) != GetStockObject( DC_PEN
)) return TRUE
;
2082 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2083 if (!(emf
->dc_pen
= CreatePenIndirect( &logpen
))) return FALSE
;
2084 if (!(index
= emfdc_create_pen( emf
, emf
->dc_pen
))) return FALSE
;
2085 GDI_hdc_using_object( emf
->dc_pen
, hdc
, emfdc_delete_object
);
2086 emr
.emr
.iType
= EMR_SELECTOBJECT
;
2087 emr
.emr
.nSize
= sizeof(emr
);
2088 emr
.ihObject
= index
;
2089 return emfdc_record( emf
, &emr
.emr
);
2092 BOOL
EMFDC_SaveDC( DC_ATTR
*dc_attr
)
2096 emr
.emr
.iType
= EMR_SAVEDC
;
2097 emr
.emr
.nSize
= sizeof(emr
);
2098 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2101 BOOL
EMFDC_RestoreDC( DC_ATTR
*dc_attr
, INT level
)
2105 if (abs(level
) > dc_attr
->save_level
|| level
== 0) return FALSE
;
2107 emr
.emr
.iType
= EMR_RESTOREDC
;
2108 emr
.emr
.nSize
= sizeof(emr
);
2110 emr
.iRelative
= level
;
2112 emr
.iRelative
= level
- dc_attr
->save_level
- 1;
2113 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2116 BOOL
EMFDC_SetTextAlign( DC_ATTR
*dc_attr
, UINT align
)
2118 EMRSETTEXTALIGN emr
;
2120 emr
.emr
.iType
= EMR_SETTEXTALIGN
;
2121 emr
.emr
.nSize
= sizeof(emr
);
2123 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2126 BOOL
EMFDC_SetTextJustification( DC_ATTR
*dc_attr
, INT extra
, INT breaks
)
2128 EMRSETTEXTJUSTIFICATION emr
;
2130 emr
.emr
.iType
= EMR_SETTEXTJUSTIFICATION
;
2131 emr
.emr
.nSize
= sizeof(emr
);
2132 emr
.nBreakExtra
= extra
;
2133 emr
.nBreakCount
= breaks
;
2134 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2137 BOOL
EMFDC_SetBkMode( DC_ATTR
*dc_attr
, INT mode
)
2141 emr
.emr
.iType
= EMR_SETBKMODE
;
2142 emr
.emr
.nSize
= sizeof(emr
);
2144 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2147 BOOL
EMFDC_SetBkColor( DC_ATTR
*dc_attr
, COLORREF color
)
2151 emr
.emr
.iType
= EMR_SETBKCOLOR
;
2152 emr
.emr
.nSize
= sizeof(emr
);
2153 emr
.crColor
= color
;
2154 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2157 BOOL
EMFDC_SetBrushOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2159 EMRSETBRUSHORGEX emr
;
2161 emr
.emr
.iType
= EMR_SETBRUSHORGEX
;
2162 emr
.emr
.nSize
= sizeof(emr
);
2163 emr
.ptlOrigin
.x
= x
;
2164 emr
.ptlOrigin
.y
= y
;
2165 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2168 BOOL
EMFDC_SetTextColor( DC_ATTR
*dc_attr
, COLORREF color
)
2170 EMRSETTEXTCOLOR emr
;
2172 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
2173 emr
.emr
.nSize
= sizeof(emr
);
2174 emr
.crColor
= color
;
2175 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2178 BOOL
EMFDC_SetROP2( DC_ATTR
*dc_attr
, INT rop
)
2182 emr
.emr
.iType
= EMR_SETROP2
;
2183 emr
.emr
.nSize
= sizeof(emr
);
2185 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2188 BOOL
EMFDC_SetPolyFillMode( DC_ATTR
*dc_attr
, INT mode
)
2190 EMRSETPOLYFILLMODE emr
;
2192 emr
.emr
.iType
= EMR_SETPOLYFILLMODE
;
2193 emr
.emr
.nSize
= sizeof(emr
);
2195 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2198 BOOL
EMFDC_SetStretchBltMode( DC_ATTR
*dc_attr
, INT mode
)
2200 EMRSETSTRETCHBLTMODE emr
;
2202 emr
.emr
.iType
= EMR_SETSTRETCHBLTMODE
;
2203 emr
.emr
.nSize
= sizeof(emr
);
2205 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2208 BOOL
EMFDC_SetArcDirection( DC_ATTR
*dc_attr
, INT dir
)
2210 EMRSETARCDIRECTION emr
;
2212 emr
.emr
.iType
= EMR_SETARCDIRECTION
;
2213 emr
.emr
.nSize
= sizeof(emr
);
2214 emr
.iArcDirection
= dir
;
2215 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2218 INT
EMFDC_ExcludeClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2220 EMREXCLUDECLIPRECT emr
;
2222 emr
.emr
.iType
= EMR_EXCLUDECLIPRECT
;
2223 emr
.emr
.nSize
= sizeof(emr
);
2224 emr
.rclClip
.left
= left
;
2225 emr
.rclClip
.top
= top
;
2226 emr
.rclClip
.right
= right
;
2227 emr
.rclClip
.bottom
= bottom
;
2228 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2231 BOOL
EMFDC_IntersectClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2233 EMRINTERSECTCLIPRECT emr
;
2235 emr
.emr
.iType
= EMR_INTERSECTCLIPRECT
;
2236 emr
.emr
.nSize
= sizeof(emr
);
2237 emr
.rclClip
.left
= left
;
2238 emr
.rclClip
.top
= top
;
2239 emr
.rclClip
.right
= right
;
2240 emr
.rclClip
.bottom
= bottom
;
2241 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2244 BOOL
EMFDC_OffsetClipRgn( DC_ATTR
*dc_attr
, INT x
, INT y
)
2246 EMROFFSETCLIPRGN emr
;
2248 emr
.emr
.iType
= EMR_OFFSETCLIPRGN
;
2249 emr
.emr
.nSize
= sizeof(emr
);
2250 emr
.ptlOffset
.x
= x
;
2251 emr
.ptlOffset
.y
= y
;
2252 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2255 BOOL
EMFDC_ExtSelectClipRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, INT mode
)
2257 EMREXTSELECTCLIPRGN
*emr
;
2258 DWORD size
, rgnsize
;
2263 if (mode
!= RGN_COPY
) return ERROR
;
2266 else rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
2268 size
= rgnsize
+ offsetof(EMREXTSELECTCLIPRGN
,RgnData
);
2269 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
2270 if (rgnsize
) NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
2272 emr
->emr
.iType
= EMR_EXTSELECTCLIPRGN
;
2273 emr
->emr
.nSize
= size
;
2274 emr
->cbRgnData
= rgnsize
;
2277 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2278 HeapFree( GetProcessHeap(), 0, emr
);
2282 BOOL
EMFDC_SetMapMode( DC_ATTR
*dc_attr
, INT mode
)
2286 emr
.emr
.iType
= EMR_SETMAPMODE
;
2287 emr
.emr
.nSize
= sizeof(emr
);
2289 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2292 BOOL
EMFDC_SetMetaRgn( DC_ATTR
*dc_attr
)
2296 emr
.emr
.iType
= EMR_SETMETARGN
;
2297 emr
.emr
.nSize
= sizeof(emr
);
2298 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2301 BOOL
EMFDC_SetMiterLimit( DC_ATTR
*dc_attr
, FLOAT limit
)
2303 struct emr_set_miter_limit emr
;
2305 emr
.emr
.iType
= EMR_SETMITERLIMIT
;
2306 emr
.emr
.nSize
= sizeof(emr
);
2307 emr
.eMiterLimit
= limit
;
2308 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2311 BOOL
EMFDC_SetViewportExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2313 EMRSETVIEWPORTEXTEX emr
;
2315 emr
.emr
.iType
= EMR_SETVIEWPORTEXTEX
;
2316 emr
.emr
.nSize
= sizeof(emr
);
2317 emr
.szlExtent
.cx
= cx
;
2318 emr
.szlExtent
.cy
= cy
;
2319 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2322 BOOL
EMFDC_SetWindowExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2324 EMRSETWINDOWEXTEX emr
;
2326 emr
.emr
.iType
= EMR_SETWINDOWEXTEX
;
2327 emr
.emr
.nSize
= sizeof(emr
);
2328 emr
.szlExtent
.cx
= cx
;
2329 emr
.szlExtent
.cy
= cy
;
2330 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2333 BOOL
EMFDC_SetViewportOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2335 EMRSETVIEWPORTORGEX emr
;
2337 emr
.emr
.iType
= EMR_SETVIEWPORTORGEX
;
2338 emr
.emr
.nSize
= sizeof(emr
);
2339 emr
.ptlOrigin
.x
= x
;
2340 emr
.ptlOrigin
.y
= y
;
2341 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2344 BOOL
EMFDC_SetWindowOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2346 EMRSETWINDOWORGEX emr
;
2348 emr
.emr
.iType
= EMR_SETWINDOWORGEX
;
2349 emr
.emr
.nSize
= sizeof(emr
);
2350 emr
.ptlOrigin
.x
= x
;
2351 emr
.ptlOrigin
.y
= y
;
2352 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2355 BOOL
EMFDC_ScaleViewportExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2357 EMRSCALEVIEWPORTEXTEX emr
;
2359 emr
.emr
.iType
= EMR_SCALEVIEWPORTEXTEX
;
2360 emr
.emr
.nSize
= sizeof(emr
);
2362 emr
.xDenom
= x_denom
;
2364 emr
.yDenom
= y_denom
;
2365 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2368 BOOL
EMFDC_ScaleWindowExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2370 EMRSCALEWINDOWEXTEX emr
;
2372 emr
.emr
.iType
= EMR_SCALEWINDOWEXTEX
;
2373 emr
.emr
.nSize
= sizeof(emr
);
2375 emr
.xDenom
= x_denom
;
2377 emr
.yDenom
= y_denom
;
2378 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2381 BOOL
EMFDC_SetLayout( DC_ATTR
*dc_attr
, DWORD layout
)
2385 emr
.emr
.iType
= EMR_SETLAYOUT
;
2386 emr
.emr
.nSize
= sizeof(emr
);
2388 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2391 BOOL
EMFDC_SetWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
)
2393 EMRSETWORLDTRANSFORM emr
;
2395 emr
.emr
.iType
= EMR_SETWORLDTRANSFORM
;
2396 emr
.emr
.nSize
= sizeof(emr
);
2398 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2401 BOOL
EMFDC_ModifyWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
, DWORD mode
)
2403 EMRMODIFYWORLDTRANSFORM emr
;
2405 emr
.emr
.iType
= EMR_MODIFYWORLDTRANSFORM
;
2406 emr
.emr
.nSize
= sizeof(emr
);
2407 if (mode
== MWT_IDENTITY
)
2409 emr
.xform
.eM11
= 1.0f
;
2410 emr
.xform
.eM12
= 0.0f
;
2411 emr
.xform
.eM21
= 0.0f
;
2412 emr
.xform
.eM22
= 1.0f
;
2413 emr
.xform
.eDx
= 0.0f
;
2414 emr
.xform
.eDy
= 0.0f
;
2421 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2424 BOOL
EMFDC_SetMapperFlags( DC_ATTR
*dc_attr
, DWORD flags
)
2426 EMRSETMAPPERFLAGS emr
;
2428 emr
.emr
.iType
= EMR_SETMAPPERFLAGS
;
2429 emr
.emr
.nSize
= sizeof(emr
);
2430 emr
.dwFlags
= flags
;
2431 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2434 BOOL
EMFDC_AbortPath( DC_ATTR
*dc_attr
)
2436 struct emf
*emf
= get_dc_emf( dc_attr
);
2439 emr
.emr
.iType
= EMR_ABORTPATH
;
2440 emr
.emr
.nSize
= sizeof(emr
);
2443 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2446 BOOL
EMFDC_BeginPath( DC_ATTR
*dc_attr
)
2448 struct emf
*emf
= get_dc_emf( dc_attr
);
2451 emr
.emr
.iType
= EMR_BEGINPATH
;
2452 emr
.emr
.nSize
= sizeof(emr
);
2453 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
2459 BOOL
EMFDC_CloseFigure( DC_ATTR
*dc_attr
)
2463 emr
.emr
.iType
= EMR_CLOSEFIGURE
;
2464 emr
.emr
.nSize
= sizeof(emr
);
2465 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2468 BOOL
EMFDC_EndPath( DC_ATTR
*dc_attr
)
2470 struct emf
*emf
= get_dc_emf( dc_attr
);
2475 emr
.emr
.iType
= EMR_ENDPATH
;
2476 emr
.emr
.nSize
= sizeof(emr
);
2477 return emfdc_record( emf
, &emr
.emr
);
2480 BOOL
EMFDC_FlattenPath( DC_ATTR
*dc_attr
)
2484 emr
.emr
.iType
= EMR_FLATTENPATH
;
2485 emr
.emr
.nSize
= sizeof(emr
);
2486 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2489 BOOL
EMFDC_SelectClipPath( DC_ATTR
*dc_attr
, INT mode
)
2491 EMRSELECTCLIPPATH emr
;
2493 emr
.emr
.iType
= EMR_SELECTCLIPPATH
;
2494 emr
.emr
.nSize
= sizeof(emr
);
2496 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2499 BOOL
EMFDC_WidenPath( DC_ATTR
*dc_attr
)
2503 emr
.emr
.iType
= EMR_WIDENPATH
;
2504 emr
.emr
.nSize
= sizeof(emr
);
2505 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2508 void EMFDC_DeleteDC( DC_ATTR
*dc_attr
)
2510 struct emf
*emf
= get_dc_emf( dc_attr
);
2513 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2514 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2515 CloseHandle( emf
->file
);
2516 HeapFree( GetProcessHeap(), 0, emf
->palette
);
2517 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2518 for (index
= 0; index
< emf
->handles_size
; index
++)
2519 if (emf
->handles
[index
])
2520 GDI_hdc_not_using_object( emf
->handles
[index
], dc_attr_handle( emf
->dc_attr
));
2521 HeapFree( GetProcessHeap(), 0, emf
->handles
);
2522 HeapFree( GetProcessHeap(), 0, emf
);
2526 /*******************************************************************
2527 * GdiComment (GDI32.@)
2529 BOOL WINAPI
GdiComment( HDC hdc
, UINT bytes
, const BYTE
*buffer
)
2536 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return FALSE
;
2538 total
= offsetof(EMRGDICOMMENT
,Data
) + aligned_size(bytes
);
2540 emr
= HeapAlloc(GetProcessHeap(), 0, total
);
2544 emr
->emr
.iType
= EMR_GDICOMMENT
;
2545 emr
->emr
.nSize
= total
;
2546 emr
->cbData
= bytes
;
2547 memcpy(&emr
->Data
[0], buffer
, bytes
);
2548 pad_record(&emr
->Data
[0], bytes
);
2550 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2552 HeapFree(GetProcessHeap(), 0, emr
);
2557 /**********************************************************************
2558 * CreateEnhMetaFileA (GDI32.@)
2560 HDC WINAPI
CreateEnhMetaFileA( HDC hdc
, const char *filename
, const RECT
*rect
,
2561 const char *description
)
2563 WCHAR
*filenameW
= NULL
;
2564 WCHAR
*descriptionW
= NULL
;
2565 DWORD len1
, len2
, total
;
2570 total
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
2571 filenameW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2572 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, total
);
2577 len1
= strlen(description
);
2578 len2
= strlen(description
+ len1
+ 1);
2579 total
= MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, NULL
, 0 );
2580 descriptionW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2581 MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, descriptionW
, total
);
2584 ret
= CreateEnhMetaFileW( hdc
, filenameW
, rect
, descriptionW
);
2586 HeapFree( GetProcessHeap(), 0, filenameW
);
2587 HeapFree( GetProcessHeap(), 0, descriptionW
);
2591 static void emf_reset( DC_ATTR
*dc_attr
, const RECT
*rect
)
2593 struct emf
*emf
= get_dc_emf( dc_attr
);
2594 HDC hdc
= dc_attr_handle( dc_attr
);
2597 for (i
= 0; i
< emf
->handles_size
; i
++)
2598 if (emf
->handles
[i
])
2599 GDI_hdc_not_using_object( emf
->handles
[i
], dc_attr_handle( emf
->dc_attr
));
2600 memset( emf
->handles
, 0, emf
->handles_size
* sizeof(emf
->handles
[0]) );
2601 emf
->cur_handles
= 1;
2603 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2605 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2608 emf
->palette_used
= 0;
2610 dc_attr
->emf_bounds
.left
= dc_attr
->emf_bounds
.top
= 0;
2611 dc_attr
->emf_bounds
.right
= dc_attr
->emf_bounds
.bottom
= -1;
2615 emf
->emh
->rclFrame
.left
= rect
->left
;
2616 emf
->emh
->rclFrame
.top
= rect
->top
;
2617 emf
->emh
->rclFrame
.right
= rect
->right
;
2618 emf
->emh
->rclFrame
.bottom
= rect
->bottom
;
2622 /* Set this to {0,0 - -1,-1} and update it at the end */
2623 emf
->emh
->rclFrame
.left
= emf
->emh
->rclFrame
.top
= 0;
2624 emf
->emh
->rclFrame
.right
= emf
->emh
->rclFrame
.bottom
= -1;
2627 emf
->emh
->dSignature
= ENHMETA_SIGNATURE
;
2628 emf
->emh
->nVersion
= 0x10000;
2629 emf
->emh
->nBytes
= emf
->emh
->nSize
;
2630 emf
->emh
->nRecords
= 1;
2631 emf
->emh
->nHandles
= 1;
2632 emf
->emh
->sReserved
= 0; /* According to docs, this is reserved and must be 0 */
2633 emf
->emh
->nPalEntries
= 0;
2635 /* Size in pixels */
2636 emf
->emh
->szlDevice
.cx
= GetDeviceCaps( hdc
, HORZRES
);
2637 emf
->emh
->szlDevice
.cy
= GetDeviceCaps( hdc
, VERTRES
);
2639 /* Size in millimeters */
2640 emf
->emh
->szlMillimeters
.cx
= GetDeviceCaps( hdc
, HORZSIZE
);
2641 emf
->emh
->szlMillimeters
.cy
= GetDeviceCaps( hdc
, VERTSIZE
);
2643 emf
->emh
->cbPixelFormat
= 0;
2644 emf
->emh
->offPixelFormat
= 0;
2645 emf
->emh
->bOpenGL
= 0;
2647 /* Size in micrometers */
2648 emf
->emh
->szlMicrometers
.cx
= emf
->emh
->szlMillimeters
.cx
* 1000;
2649 emf
->emh
->szlMicrometers
.cy
= emf
->emh
->szlMillimeters
.cy
* 1000;
2652 static struct emf
*emf_create( HDC hdc
, const RECT
*rect
, const WCHAR
*description
)
2654 DWORD size
= 0, length
= 0;
2659 if (!(dc_attr
= get_dc_attr( hdc
)) || !(emf
= HeapAlloc( GetProcessHeap(), 0, sizeof(*emf
) )))
2662 if (description
) /* App name\0Title\0\0 */
2664 length
= lstrlenW( description
);
2665 length
+= lstrlenW( description
+ length
+ 1 );
2669 size
= sizeof(ENHMETAHEADER
) + aligned_size(length
);
2671 if (!(emf
->emh
= HeapAlloc( GetProcessHeap(), 0, size
)) ||
2672 !(emf
->handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
2673 HANDLE_LIST_INC
* sizeof(emf
->handles
[0]) )))
2675 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2676 HeapFree( GetProcessHeap(), 0, emf
);
2680 emf
->dc_attr
= dc_attr
;
2681 dc_attr
->emf
= (UINT_PTR
)emf
;
2683 emf
->handles_size
= HANDLE_LIST_INC
;
2686 emf
->palette_size
= 0;
2687 emf
->palette
= NULL
;
2689 emf
->emh
->iType
= EMR_HEADER
;
2690 emf
->emh
->nSize
= size
;
2691 emf
->emh
->nDescription
= length
/ 2;
2692 emf
->emh
->offDescription
= length
? sizeof(ENHMETAHEADER
) : 0;
2694 ptr
= memcpy( (char *)emf
->emh
+ sizeof(ENHMETAHEADER
), description
, length
);
2695 pad_record( ptr
, length
);
2697 emf_reset( dc_attr
, rect
);
2701 /**********************************************************************
2702 * CreateEnhMetaFileW (GDI32.@)
2704 HDC WINAPI
CreateEnhMetaFileW( HDC hdc
, const WCHAR
*filename
, const RECT
*rect
,
2705 const WCHAR
*description
)
2711 TRACE( "(%p %s %s %s)\n", hdc
, debugstr_w(filename
), wine_dbgstr_rect(rect
),
2712 debugstr_w(description
) );
2714 if (!(ret
= NtGdiCreateMetafileDC( hdc
))) return 0;
2716 emf
= emf_create( ret
, rect
, description
);
2723 if (filename
) /* disk based metafile */
2725 if ((file
= CreateFileW( filename
, GENERIC_WRITE
| GENERIC_READ
, 0,
2726 NULL
, CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
)
2734 TRACE( "returning %p\n", ret
);
2738 static BOOL
emf_eof( DC_ATTR
*dc_attr
)
2740 struct emf
*emf
= get_dc_emf( dc_attr
);
2741 UINT size
, palette_size
;
2745 palette_size
= emf
->palette_used
* sizeof(*emf
->palette
);
2746 size
= sizeof(*emr
) + palette_size
;
2747 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
2749 emr
->emr
.iType
= EMR_EOF
;
2750 emr
->emr
.nSize
= size
;
2751 emr
->nPalEntries
= emf
->palette_used
;
2752 emr
->offPalEntries
= FIELD_OFFSET(EMREOF
, nSizeLast
);
2753 memcpy( (BYTE
*)emr
+ emr
->offPalEntries
, emf
->palette
, palette_size
);
2755 ((DWORD
*)((BYTE
*)emr
+ size
))[-1] = size
;
2756 ret
= emfdc_record( emf
, &emr
->emr
);
2757 HeapFree( GetProcessHeap(), 0, emr
);
2758 if (!ret
) return FALSE
;
2760 emf
->emh
->rclBounds
= dc_attr
->emf_bounds
;
2762 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2763 if (emf
->emh
->rclFrame
.left
> emf
->emh
->rclFrame
.right
)
2765 emf
->emh
->rclFrame
.left
= emf
->emh
->rclBounds
.left
*
2766 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2767 emf
->emh
->rclFrame
.top
= emf
->emh
->rclBounds
.top
*
2768 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2769 emf
->emh
->rclFrame
.right
= emf
->emh
->rclBounds
.right
*
2770 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2771 emf
->emh
->rclFrame
.bottom
= emf
->emh
->rclBounds
.bottom
*
2772 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2777 /******************************************************************
2778 * CloseEnhMetaFile (GDI32.@)
2780 HENHMETAFILE WINAPI
CloseEnhMetaFile( HDC hdc
)
2787 TRACE("(%p)\n", hdc
);
2789 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return 0;
2790 emf
= get_dc_emf( dc_attr
);
2792 if (dc_attr
->save_level
)
2793 RestoreDC( hdc
, 1 );
2795 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2797 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2800 if (!emf_eof( dc_attr
)) return 0;
2802 if (emf
->file
) /* disk based metafile */
2804 if (!WriteFile( emf
->file
, emf
->emh
, emf
->emh
->nBytes
, NULL
, NULL
))
2806 CloseHandle( emf
->file
);
2810 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2811 mapping
= CreateFileMappingA( emf
->file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
2812 TRACE( "mapping = %p\n", mapping
);
2813 emf
->emh
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
2814 TRACE( "view = %p\n", emf
->emh
);
2815 CloseHandle( mapping
);
2816 CloseHandle( emf
->file
);
2819 hmf
= EMF_Create_HENHMETAFILE( emf
->emh
, emf
->emh
->nBytes
, emf
->file
!= 0 );
2821 emf
->emh
= NULL
; /* So it won't be deleted */
2826 BOOL
spool_start_doc( DC_ATTR
*dc_attr
, HANDLE hspool
, const DOCINFOW
*doc_info
)
2830 unsigned int dwVersion
;
2831 unsigned int cjSize
;
2832 unsigned int dpszDocName
;
2833 unsigned int dpszOutput
;
2835 size_t size
= sizeof(*header
);
2840 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2842 if (doc_info
->lpszDocName
)
2843 size
+= (wcslen( doc_info
->lpszDocName
) + 1) * sizeof(WCHAR
);
2844 if (doc_info
->lpszOutput
)
2845 size
+= (wcslen( doc_info
->lpszOutput
) + 1) * sizeof(WCHAR
);
2846 header
= HeapAlloc( GetProcessHeap(), 0, size
);
2847 if (!header
) return FALSE
;
2849 header
->dwVersion
= 0x10000;
2850 header
->cjSize
= size
;
2851 p
= (WCHAR
*)(header
+ 1);
2852 if (doc_info
->lpszDocName
)
2854 header
->dpszDocName
= (BYTE
*)p
- (BYTE
*)header
;
2855 wcscpy( p
, doc_info
->lpszDocName
);
2856 p
+= wcslen( doc_info
->lpszDocName
) + 1;
2860 header
->dpszDocName
= 0;
2862 if (doc_info
->lpszOutput
)
2864 header
->dpszOutput
= (BYTE
*)p
- (BYTE
*)header
;
2865 wcscpy( p
, doc_info
->lpszOutput
);
2869 header
->dpszOutput
= 0;
2871 if (!WritePrinter( hspool
, header
, size
, &written
)) written
= 0;
2872 HeapFree( GetProcessHeap(), 0, header
);
2873 if (written
!= size
) return FALSE
;
2875 emf
= emf_create( dc_attr_handle(dc_attr
), NULL
, NULL
);
2876 if (!emf
) return FALSE
;
2880 int spool_start_page( DC_ATTR
*dc_attr
, HANDLE hspool
)
2882 HDC hdc
= dc_attr_handle( dc_attr
);
2886 TRACE( "(%p)\n", dc_attr
);
2888 /* Save current DC state to EMF */
2889 /* FIXME: SetTextJustification if needed */
2890 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_PEN
) );
2891 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_BRUSH
) );
2892 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_FONT
) );
2893 if (GetBkColor( hdc
) != 0xffffff)
2894 EMFDC_SetBkColor( dc_attr
, GetBkColor(hdc
) );
2895 if (GetBkMode( hdc
) != OPAQUE
)
2896 EMFDC_SetBkMode( dc_attr
, GetBkMode(hdc
) );
2897 GetCurrentPositionEx( hdc
, &pos
);
2899 EMFDC_MoveTo( dc_attr
, pos
.x
, pos
.y
);
2900 if (GetMapMode( hdc
) != MM_TEXT
)
2901 EMFDC_SetMapMode( dc_attr
, GetMapMode(hdc
) );
2902 if (GetPolyFillMode( hdc
) != ALTERNATE
)
2903 EMFDC_SetPolyFillMode( dc_attr
, GetPolyFillMode(hdc
) );
2904 if (GetROP2( hdc
) != R2_COPYPEN
)
2905 EMFDC_SetROP2( dc_attr
, GetROP2(hdc
) );
2906 if (GetStretchBltMode( hdc
) != BLACKONWHITE
)
2907 EMFDC_SetStretchBltMode( dc_attr
, GetStretchBltMode(hdc
) );
2908 if (GetTextAlign( hdc
) != (TA_LEFT
| TA_TOP
))
2909 EMFDC_SetTextAlign( dc_attr
, GetTextAlign(hdc
) );
2910 if (GetTextColor( hdc
))
2911 EMFDC_SetTextColor( dc_attr
, GetTextColor(hdc
) );
2912 GetWorldTransform(hdc
, &xform
);
2913 if (xform
.eM11
!= 1 || xform
.eM22
!= 1 || xform
.eM12
|| xform
.eM21
|| xform
.eDx
|| xform
.eDy
)
2914 EMFDC_SetWorldTransform( dc_attr
, &xform
);
2916 return StartPagePrinter( hspool
);
2919 int spool_end_page( DC_ATTR
*dc_attr
, HANDLE hspool
, const DEVMODEW
*devmode
, BOOL write_devmode
)
2924 unsigned int cjSize
;
2928 struct record_hdr hdr
;
2931 struct emf
*emf
= get_dc_emf( dc_attr
);
2934 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2936 if (!emf_eof( dc_attr
)) return 0;
2938 record_hdr
.ulID
= EMRI_METAFILE_DATA
;
2939 record_hdr
.cjSize
= emf
->emh
->nBytes
;
2940 if (!WritePrinter( hspool
, &record_hdr
, sizeof(record_hdr
), &written
)) return 0;
2941 if (!WritePrinter( hspool
, emf
->emh
, emf
->emh
->nBytes
, &written
)) return 0;
2945 record_hdr
.ulID
= EMRI_DEVMODE
;
2946 record_hdr
.cjSize
= devmode
? devmode
->dmSize
+ devmode
->dmDriverExtra
: 0;
2947 if (!WritePrinter( hspool
, &record_hdr
, sizeof(record_hdr
), &written
)) return 0;
2948 if (devmode
&& !WritePrinter( hspool
, (BYTE
*)devmode
,
2949 record_hdr
.cjSize
, &written
)) return 0;
2952 metafile_ext
.hdr
.ulID
= EMRI_METAFILE_EXT
;
2953 metafile_ext
.hdr
.cjSize
= sizeof(metafile_ext
) - sizeof(struct record_hdr
);
2954 metafile_ext
.pos
.QuadPart
= emf
->emh
->nBytes
+ sizeof(record_hdr
);
2956 metafile_ext
.pos
.QuadPart
+= record_hdr
.cjSize
+ sizeof(record_hdr
);
2957 if (!WritePrinter( hspool
, &metafile_ext
, sizeof(metafile_ext
), &written
)) return 0;
2959 emf_reset( dc_attr
, NULL
);
2960 return EndPagePrinter( hspool
);
2963 int spool_abort_doc( DC_ATTR
*dc_attr
, HANDLE hspool
)
2965 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2967 EMFDC_DeleteDC( dc_attr
);
2968 return AbortPrinter( hspool
);
2971 int spool_end_doc( DC_ATTR
*dc_attr
, HANDLE hspool
)
2973 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2975 EMFDC_DeleteDC( dc_attr
);
2976 return EndDocPrinter( hspool
);