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
;
61 EMRI_BW_FORM_METAFILE
,
67 EMRI_DESIGNVECTOR_EXT
,
72 } emfspool_record_type
;
74 #define HANDLE_LIST_INC 20
75 static const RECTL empty_bounds
= { 0, 0, -1, -1 };
77 static struct emf
*get_dc_emf( DC_ATTR
*dc_attr
)
79 return (struct emf
*)(UINT_PTR
)dc_attr
->emf
;
82 static HDC
dc_attr_handle( DC_ATTR
*dc_attr
)
84 return UlongToHandle( dc_attr
->hdc
);
87 static BOOL
emfdc_record( struct emf
*emf
, EMR
*emr
)
92 TRACE( "record %ld, size %ld\n", emr
->iType
, emr
->nSize
);
94 assert( !(emr
->nSize
& 3) );
96 emf
->emh
->nBytes
+= emr
->nSize
;
99 size
= HeapSize( GetProcessHeap(), 0, emf
->emh
);
100 len
= emf
->emh
->nBytes
;
103 size
+= (size
/ 2) + emr
->nSize
;
104 emh
= HeapReAlloc( GetProcessHeap(), 0, emf
->emh
, size
);
105 if (!emh
) return FALSE
;
108 memcpy( (char *)emf
->emh
+ emf
->emh
->nBytes
- emr
->nSize
, emr
, emr
->nSize
);
112 static void emfdc_update_bounds( struct emf
*emf
, RECTL
*rect
)
114 RECTL
*bounds
= &emf
->dc_attr
->emf_bounds
;
115 RECTL vport_rect
= *rect
;
117 LPtoDP( dc_attr_handle( emf
->dc_attr
), (POINT
*)&vport_rect
, 2 );
119 /* The coordinate systems may be mirrored
120 (LPtoDP handles points, not rectangles) */
121 if (vport_rect
.left
> vport_rect
.right
)
123 LONG temp
= vport_rect
.right
;
124 vport_rect
.right
= vport_rect
.left
;
125 vport_rect
.left
= temp
;
127 if (vport_rect
.top
> vport_rect
.bottom
)
129 LONG temp
= vport_rect
.bottom
;
130 vport_rect
.bottom
= vport_rect
.top
;
131 vport_rect
.top
= temp
;
134 if (bounds
->left
> bounds
->right
)
136 /* first bounding rectangle */
137 *bounds
= vport_rect
;
141 bounds
->left
= min(bounds
->left
, vport_rect
.left
);
142 bounds
->top
= min(bounds
->top
, vport_rect
.top
);
143 bounds
->right
= max(bounds
->right
, vport_rect
.right
);
144 bounds
->bottom
= max(bounds
->bottom
, vport_rect
.bottom
);
148 static UINT
get_bitmap_info( HDC
*hdc
, HBITMAP
*bitmap
, BITMAPINFO
*info
)
155 if (!(info_size
= GetObjectW( *bitmap
, sizeof(dib
), &dib
))) return 0;
157 if (info_size
== sizeof(dib
))
160 blit_bitmap
= *bitmap
;
164 unsigned char dib_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
165 BITMAPINFO
*dib_info
= (BITMAPINFO
*)dib_info_buffer
;
166 BITMAP bmp
= dib
.dsBm
;
170 assert( info_size
== sizeof(BITMAP
) );
172 dib_info
->bmiHeader
.biSize
= sizeof(dib_info
->bmiHeader
);
173 dib_info
->bmiHeader
.biWidth
= bmp
.bmWidth
;
174 dib_info
->bmiHeader
.biHeight
= bmp
.bmHeight
;
175 dib_info
->bmiHeader
.biPlanes
= 1;
176 dib_info
->bmiHeader
.biBitCount
= bmp
.bmBitsPixel
;
177 dib_info
->bmiHeader
.biCompression
= BI_RGB
;
178 dib_info
->bmiHeader
.biSizeImage
= 0;
179 dib_info
->bmiHeader
.biXPelsPerMeter
= 0;
180 dib_info
->bmiHeader
.biYPelsPerMeter
= 0;
181 dib_info
->bmiHeader
.biClrUsed
= 0;
182 dib_info
->bmiHeader
.biClrImportant
= 0;
183 switch (dib_info
->bmiHeader
.biBitCount
)
186 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xf800;
187 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x07e0;
188 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x001f;
191 ((DWORD
*)dib_info
->bmiColors
)[0] = 0xff0000;
192 ((DWORD
*)dib_info
->bmiColors
)[1] = 0x00ff00;
193 ((DWORD
*)dib_info
->bmiColors
)[2] = 0x0000ff;
196 if (dib_info
->bmiHeader
.biBitCount
> 8) break;
197 if (!(palette
= GetCurrentObject( *hdc
, OBJ_PAL
))) return FALSE
;
198 if (!GetPaletteEntries( palette
, 0, 256, (PALETTEENTRY
*)dib_info
->bmiColors
))
202 if (!(blit_dc
= NtGdiCreateCompatibleDC( *hdc
))) return FALSE
;
203 if (!(blit_bitmap
= CreateDIBSection( blit_dc
, dib_info
, DIB_RGB_COLORS
, &bits
, NULL
, 0 )))
205 if (!SelectObject( blit_dc
, blit_bitmap
)) goto err
;
206 if (!BitBlt( blit_dc
, 0, 0, bmp
.bmWidth
, bmp
.bmHeight
, *hdc
, 0, 0, SRCCOPY
))
209 if (!GetDIBits( blit_dc
, blit_bitmap
, 0, INT_MAX
, NULL
, info
, DIB_RGB_COLORS
))
212 bpp
= info
->bmiHeader
.biBitCount
;
214 return sizeof(BITMAPINFOHEADER
) + (1 << bpp
) * sizeof(RGBQUAD
);
215 else if (bpp
== 16 || bpp
== 32)
216 return sizeof(BITMAPINFOHEADER
) + 3 * sizeof(RGBQUAD
);
218 return sizeof(BITMAPINFOHEADER
);
221 if (blit_dc
&& blit_dc
!= *hdc
) DeleteDC( blit_dc
);
222 if (blit_bitmap
&& blit_bitmap
!= *bitmap
) DeleteObject( blit_bitmap
);
226 /*******************************************************************************************
227 * Verify that the DIB parameters are valid.
229 static BOOL
is_valid_dib_format( const BITMAPINFOHEADER
*info
, BOOL allow_compression
)
231 if (info
->biWidth
<= 0) return FALSE
;
232 if (info
->biHeight
== 0) return FALSE
;
234 if (allow_compression
&& (info
->biCompression
== BI_RLE4
|| info
->biCompression
== BI_RLE8
))
236 if (info
->biHeight
< 0) return FALSE
;
237 if (!info
->biSizeImage
) return FALSE
;
238 return info
->biBitCount
== (info
->biCompression
== BI_RLE4
? 4 : 8);
241 if (!info
->biPlanes
) return FALSE
;
243 /* check for size overflow */
244 if (!info
->biBitCount
) return FALSE
;
245 if (UINT_MAX
/ info
->biBitCount
< info
->biWidth
) return FALSE
;
246 if (UINT_MAX
/ get_dib_stride( info
->biWidth
, info
->biBitCount
) < abs( info
->biHeight
)) return FALSE
;
248 switch (info
->biBitCount
)
254 return (info
->biCompression
== BI_RGB
);
257 return (info
->biCompression
== BI_BITFIELDS
|| info
->biCompression
== BI_RGB
);
263 static BOOL
emf_parse_user_bitmapinfo( BITMAPINFOHEADER
*dst
, const BITMAPINFOHEADER
*info
,
264 UINT coloruse
, BOOL allow_compression
,
265 UINT
*bmi_size
, UINT
*img_size
)
267 UINT colour_table_size
;
269 if (coloruse
> DIB_PAL_COLORS
+ 1) return FALSE
; /* FIXME: handle DIB_PAL_COLORS+1 format */
270 if (!info
) return FALSE
;
272 memset(dst
, 0, sizeof(*dst
));
274 if (info
->biSize
== sizeof(BITMAPCOREHEADER
))
276 const BITMAPCOREHEADER
*core
= (const BITMAPCOREHEADER
*)info
;
277 dst
->biWidth
= core
->bcWidth
;
278 dst
->biHeight
= core
->bcHeight
;
279 dst
->biPlanes
= core
->bcPlanes
;
280 dst
->biBitCount
= core
->bcBitCount
;
281 dst
->biCompression
= BI_RGB
;
282 dst
->biXPelsPerMeter
= 0;
283 dst
->biYPelsPerMeter
= 0;
285 dst
->biClrImportant
= 0;
287 else if (info
->biSize
>= sizeof(BITMAPINFOHEADER
)) /* assume BITMAPINFOHEADER */
293 WARN( "(%lu): unknown/wrong size for header\n", info
->biSize
);
297 dst
->biSize
= sizeof(*dst
);
299 if (!is_valid_dib_format( dst
, allow_compression
)) return FALSE
;
301 colour_table_size
= 0;
302 if (dst
->biCompression
== BI_BITFIELDS
)
304 colour_table_size
= 3 * sizeof(DWORD
);
306 else if (dst
->biBitCount
<= 8)
308 UINT elm_size
= coloruse
== DIB_PAL_COLORS
? sizeof(WORD
) : sizeof(DWORD
);
309 UINT colours
= dst
->biClrUsed
;
311 /* Windows never truncates colour tables, even if they are
312 * unnecessarily big (> 1<<bpp). We emulate this behaviour. */
314 if (colours
> UINT_MAX
/ elm_size
)
316 WARN( "too many colours in palette (%u > %u)\n",
317 colours
, UINT_MAX
/ elm_size
);
321 colour_table_size
= colours
* elm_size
;
324 *bmi_size
= sizeof(BITMAPINFOHEADER
) + colour_table_size
;
325 if (*bmi_size
< sizeof(BITMAPINFOHEADER
))
328 if (dst
->biCompression
== BI_RGB
|| dst
->biCompression
== BI_BITFIELDS
)
329 *img_size
= get_dib_stride( dst
->biWidth
, dst
->biBitCount
) * abs( dst
->biHeight
);
331 *img_size
= dst
->biSizeImage
;
336 static void emf_copy_colours_from_user_bitmapinfo( BITMAPINFO
*dst
, const BITMAPINFO
*info
, UINT coloruse
)
338 if (dst
->bmiHeader
.biCompression
== BI_BITFIELDS
)
340 /* bitfields are always at bmiColors even in larger structures */
341 memcpy( dst
->bmiColors
, info
->bmiColors
, 3 * sizeof(DWORD
) );
343 else if (dst
->bmiHeader
.biBitCount
<= 8)
345 void *src_colors
= (char *)info
+ info
->bmiHeader
.biSize
;
346 unsigned int colors
= dst
->bmiHeader
.biClrUsed
;
348 if (!colors
) colors
= 1 << dst
->bmiHeader
.biBitCount
;
350 if (coloruse
== DIB_PAL_COLORS
)
352 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(WORD
) );
354 else if (info
->bmiHeader
.biSize
!= sizeof(BITMAPCOREHEADER
))
356 memcpy( dst
->bmiColors
, src_colors
, colors
* sizeof(RGBQUAD
) );
361 RGBTRIPLE
*triple
= (RGBTRIPLE
*)src_colors
;
362 for (i
= 0; i
< colors
; i
++)
364 dst
->bmiColors
[i
].rgbRed
= triple
[i
].rgbtRed
;
365 dst
->bmiColors
[i
].rgbGreen
= triple
[i
].rgbtGreen
;
366 dst
->bmiColors
[i
].rgbBlue
= triple
[i
].rgbtBlue
;
367 dst
->bmiColors
[i
].rgbReserved
= 0;
373 static UINT
emfdc_add_handle( struct emf
*emf
, HGDIOBJ obj
)
377 for (index
= 0; index
< emf
->handles_size
; index
++)
378 if (emf
->handles
[index
] == 0) break;
380 if (index
== emf
->handles_size
)
382 emf
->handles_size
+= HANDLE_LIST_INC
;
383 emf
->handles
= HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
,
385 emf
->handles_size
* sizeof(emf
->handles
[0]) );
387 emf
->handles
[index
] = obj
;
390 if (emf
->cur_handles
> emf
->emh
->nHandles
)
391 emf
->emh
->nHandles
++;
393 return index
+ 1; /* index 0 is reserved for the hmf, so we increment everything by 1 */
396 static UINT
emfdc_find_object( struct emf
*emf
, HGDIOBJ obj
)
400 for (index
= 0; index
< emf
->handles_size
; index
++)
401 if (emf
->handles
[index
] == obj
) return index
+ 1;
406 static void emfdc_delete_object( HDC hdc
, HGDIOBJ obj
)
408 DC_ATTR
*dc_attr
= get_dc_attr( hdc
);
409 struct emf
*emf
= get_dc_emf( dc_attr
);
413 if(!(index
= emfdc_find_object( emf
, obj
))) return;
415 emr
.emr
.iType
= EMR_DELETEOBJECT
;
416 emr
.emr
.nSize
= sizeof(emr
);
417 emr
.ihObject
= index
;
419 emfdc_record( emf
, &emr
.emr
);
421 emf
->handles
[index
- 1] = 0;
425 static BOOL
emfdc_add_palette_entry( struct emf
*emf
, PALETTEENTRY
*entry
)
429 for (i
= 0; i
< emf
->palette_used
; i
++)
431 if (emf
->palette
[i
].peRed
== entry
->peRed
&&
432 emf
->palette
[i
].peGreen
== entry
->peGreen
&&
433 emf
->palette
[i
].peBlue
== entry
->peBlue
) return TRUE
;
436 if (emf
->palette_size
== emf
->palette_used
)
438 if (!emf
->palette_size
)
440 emf
->palette
= HeapAlloc( GetProcessHeap(), 0,
441 8 * sizeof(*emf
->palette
) );
442 if (!emf
->palette
) return FALSE
;
443 emf
->palette_size
= 8;
447 void *new_palette
= HeapReAlloc( GetProcessHeap(), 0, emf
->palette
,
448 2 * emf
->palette_size
* sizeof(*emf
->palette
) );
449 if (!new_palette
) return FALSE
;
450 emf
->palette
= new_palette
;
451 emf
->palette_size
*= 2;
455 emf
->palette
[emf
->palette_used
++] = *entry
;
459 static DWORD
emfdc_create_brush( struct emf
*emf
, HBRUSH brush
)
464 if (!GetObjectA( brush
, sizeof(logbrush
), &logbrush
)) return 0;
466 switch (logbrush
.lbStyle
) {
471 EMRCREATEBRUSHINDIRECT emr
;
472 emr
.emr
.iType
= EMR_CREATEBRUSHINDIRECT
;
473 emr
.emr
.nSize
= sizeof(emr
);
474 emr
.ihBrush
= index
= emfdc_add_handle( emf
, brush
);
475 emr
.lb
.lbStyle
= logbrush
.lbStyle
;
476 emr
.lb
.lbColor
= logbrush
.lbColor
;
477 emr
.lb
.lbHatch
= logbrush
.lbHatch
;
479 if(!emfdc_record( emf
, &emr
.emr
))
486 EMRCREATEDIBPATTERNBRUSHPT
*emr
;
487 char buffer
[FIELD_OFFSET( BITMAPINFO
, bmiColors
[256] )];
488 BITMAPINFO
*info
= (BITMAPINFO
*)buffer
;
492 if (!NtGdiIcmBrushInfo( 0, brush
, info
, NULL
, NULL
, &usage
, NULL
, 0 )) break;
493 info_size
= get_dib_info_size( info
, usage
);
495 emr
= HeapAlloc( GetProcessHeap(), 0,
496 sizeof(EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
) +
497 info_size
+info
->bmiHeader
.biSizeImage
);
500 /* FIXME: There is an extra DWORD written by native before the BMI.
501 * Not sure what it's meant to contain.
503 emr
->offBmi
= sizeof( EMRCREATEDIBPATTERNBRUSHPT
) + sizeof(DWORD
);
504 *(DWORD
*)(emr
+ 1) = 0x20000000;
506 if (logbrush
.lbStyle
== BS_PATTERN
&& info
->bmiHeader
.biBitCount
== 1)
508 /* Presumably to reduce the size of the written EMF, MS supports an
509 * undocumented iUsage value of 2, indicating a mono bitmap without the
510 * 8 byte 2 entry black/white palette. Stupidly, they could have saved
511 * over 20 bytes more by also ignoring the BITMAPINFO fields that are
512 * irrelevant/constant for monochrome bitmaps.
513 * FIXME: It may be that the DIB functions themselves accept this value.
515 emr
->emr
.iType
= EMR_CREATEMONOBRUSH
;
516 usage
= DIB_PAL_INDICES
;
517 emr
->cbBmi
= sizeof( BITMAPINFOHEADER
);
521 emr
->emr
.iType
= EMR_CREATEDIBPATTERNBRUSHPT
;
522 emr
->cbBmi
= info_size
;
524 emr
->ihBrush
= index
= emfdc_add_handle( emf
, brush
);
526 emr
->offBits
= emr
->offBmi
+ emr
->cbBmi
;
527 emr
->cbBits
= info
->bmiHeader
.biSizeImage
;
528 emr
->emr
.nSize
= emr
->offBits
+ emr
->cbBits
;
530 if (info
->bmiHeader
.biClrUsed
== 1 << info
->bmiHeader
.biBitCount
)
531 info
->bmiHeader
.biClrUsed
= 0;
532 memcpy( (BYTE
*)emr
+ emr
->offBmi
, info
, emr
->cbBmi
);
533 NtGdiIcmBrushInfo( 0, brush
, NULL
, (char *)emr
+ emr
->offBits
, NULL
, NULL
, NULL
, 0 );
535 if (!emfdc_record( emf
, &emr
->emr
)) index
= 0;
536 HeapFree( GetProcessHeap(), 0, emr
);
541 FIXME("Unknown style %x\n", logbrush
.lbStyle
);
548 static BOOL
emfdc_select_brush( DC_ATTR
*dc_attr
, HBRUSH brush
)
550 struct emf
*emf
= get_dc_emf( dc_attr
);
555 /* If the object is a stock brush object, do not need to create it.
556 * See definitions in wingdi.h for range of stock brushes.
557 * We do however have to handle setting the higher order bit to
558 * designate that this is a stock object.
560 for (i
= WHITE_BRUSH
; i
<= DC_BRUSH
; i
++)
562 if (brush
== GetStockObject(i
))
564 index
= i
| 0x80000000;
569 if (!index
&& !(index
= emfdc_find_object( emf
, brush
)))
571 if (!(index
= emfdc_create_brush( emf
, brush
))) return 0;
572 GDI_hdc_using_object( brush
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
575 emr
.emr
.iType
= EMR_SELECTOBJECT
;
576 emr
.emr
.nSize
= sizeof(emr
);
577 emr
.ihObject
= index
;
578 return emfdc_record( emf
, &emr
.emr
);
581 static BOOL
emfdc_create_font( struct emf
*emf
, HFONT font
)
584 EMREXTCREATEFONTINDIRECTW emr
;
587 if (!GetObjectW( font
, sizeof(emr
.elfw
.elfLogFont
), &emr
.elfw
.elfLogFont
)) return FALSE
;
589 emr
.emr
.iType
= EMR_EXTCREATEFONTINDIRECTW
;
590 emr
.emr
.nSize
= (sizeof(emr
) + 3) / 4 * 4;
591 emr
.ihFont
= index
= emfdc_add_handle( emf
, font
);
592 emr
.elfw
.elfFullName
[0] = '\0';
593 emr
.elfw
.elfStyle
[0] = '\0';
594 emr
.elfw
.elfVersion
= 0;
595 emr
.elfw
.elfStyleSize
= 0;
596 emr
.elfw
.elfMatch
= 0;
597 emr
.elfw
.elfReserved
= 0;
598 for (i
= 0; i
< ELF_VENDOR_SIZE
; i
++)
599 emr
.elfw
.elfVendorId
[i
] = 0;
600 emr
.elfw
.elfCulture
= PAN_CULTURE_LATIN
;
601 emr
.elfw
.elfPanose
.bFamilyType
= PAN_NO_FIT
;
602 emr
.elfw
.elfPanose
.bSerifStyle
= PAN_NO_FIT
;
603 emr
.elfw
.elfPanose
.bWeight
= PAN_NO_FIT
;
604 emr
.elfw
.elfPanose
.bProportion
= PAN_NO_FIT
;
605 emr
.elfw
.elfPanose
.bContrast
= PAN_NO_FIT
;
606 emr
.elfw
.elfPanose
.bStrokeVariation
= PAN_NO_FIT
;
607 emr
.elfw
.elfPanose
.bArmStyle
= PAN_NO_FIT
;
608 emr
.elfw
.elfPanose
.bLetterform
= PAN_NO_FIT
;
609 emr
.elfw
.elfPanose
.bMidline
= PAN_NO_FIT
;
610 emr
.elfw
.elfPanose
.bXHeight
= PAN_NO_FIT
;
612 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
615 static BOOL
emfdc_select_font( DC_ATTR
*dc_attr
, HFONT font
)
617 struct emf
*emf
= get_dc_emf( dc_attr
);
622 /* If the object is a stock font object, do not need to create it.
623 * See definitions in wingdi.h for range of stock fonts.
624 * We do however have to handle setting the higher order bit to
625 * designate that this is a stock object.
628 for (i
= OEM_FIXED_FONT
; i
<= DEFAULT_GUI_FONT
; i
++)
630 if (i
!= DEFAULT_PALETTE
&& font
== GetStockObject(i
))
632 index
= i
| 0x80000000;
637 if (!(index
= emfdc_find_object( emf
, font
)))
639 if (!(index
= emfdc_create_font( emf
, font
))) return FALSE
;
640 GDI_hdc_using_object( font
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
644 emr
.emr
.iType
= EMR_SELECTOBJECT
;
645 emr
.emr
.nSize
= sizeof(emr
);
646 emr
.ihObject
= index
;
647 return emfdc_record( emf
, &emr
.emr
);
650 static DWORD
emfdc_create_pen( struct emf
*emf
, HPEN hPen
)
655 if (!GetObjectW( hPen
, sizeof(emr
.lopn
), &emr
.lopn
))
657 /* must be an extended pen */
659 INT size
= GetObjectW( hPen
, 0, NULL
);
663 elp
= HeapAlloc( GetProcessHeap(), 0, size
);
665 GetObjectW( hPen
, size
, elp
);
666 /* FIXME: add support for user style pens */
667 emr
.lopn
.lopnStyle
= elp
->elpPenStyle
;
668 emr
.lopn
.lopnWidth
.x
= elp
->elpWidth
;
669 emr
.lopn
.lopnWidth
.y
= 0;
670 emr
.lopn
.lopnColor
= elp
->elpColor
;
672 HeapFree( GetProcessHeap(), 0, elp
);
675 emr
.emr
.iType
= EMR_CREATEPEN
;
676 emr
.emr
.nSize
= sizeof(emr
);
677 emr
.ihPen
= index
= emfdc_add_handle( emf
, hPen
);
678 return emfdc_record( emf
, &emr
.emr
) ? index
: 0;
681 static BOOL
emfdc_select_pen( DC_ATTR
*dc_attr
, HPEN pen
)
683 struct emf
*emf
= get_dc_emf( dc_attr
);
688 /* If the object is a stock pen object, do not need to create it.
689 * See definitions in wingdi.h for range of stock pens.
690 * We do however have to handle setting the higher order bit to
691 * designate that this is a stock object.
694 for (i
= WHITE_PEN
; i
<= DC_PEN
; i
++)
696 if (pen
== GetStockObject(i
))
698 index
= i
| 0x80000000;
702 if (!index
&& !(index
= emfdc_find_object( emf
, pen
)))
704 if (!(index
= emfdc_create_pen( emf
, pen
))) return FALSE
;
705 GDI_hdc_using_object( pen
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
708 emr
.emr
.iType
= EMR_SELECTOBJECT
;
709 emr
.emr
.nSize
= sizeof(emr
);
710 emr
.ihObject
= index
;
711 return emfdc_record( emf
, &emr
.emr
);
714 static DWORD
emfdc_create_palette( struct emf
*emf
, HPALETTE hPal
)
716 BYTE data
[offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[256] )];
717 EMRCREATEPALETTE
*hdr
= (EMRCREATEPALETTE
*)data
;
720 memset( data
, 0, sizeof(data
) );
722 hdr
->lgpl
.palVersion
= 0x300;
723 hdr
->lgpl
.palNumEntries
= GetPaletteEntries( hPal
, 0, 256, hdr
->lgpl
.palPalEntry
);
724 if (!hdr
->lgpl
.palNumEntries
)
727 for (i
= 0; i
< hdr
->lgpl
.palNumEntries
; i
++)
729 hdr
->lgpl
.palPalEntry
[i
].peFlags
= 0;
730 emfdc_add_palette_entry( emf
, hdr
->lgpl
.palPalEntry
+ i
);
733 hdr
->emr
.iType
= EMR_CREATEPALETTE
;
734 hdr
->emr
.nSize
= offsetof( EMRCREATEPALETTE
, lgpl
.palPalEntry
[hdr
->lgpl
.palNumEntries
] );
735 hdr
->ihPal
= emfdc_add_handle( emf
, hPal
);
737 if (!emfdc_record( emf
, &hdr
->emr
))
742 BOOL
EMFDC_SelectPalette( DC_ATTR
*dc_attr
, HPALETTE palette
)
744 struct emf
*emf
= get_dc_emf( dc_attr
);
745 EMRSELECTPALETTE emr
;
748 if (palette
== GetStockObject( DEFAULT_PALETTE
))
750 index
= DEFAULT_PALETTE
| 0x80000000;
752 else if (!(index
= emfdc_find_object( emf
, palette
)))
754 if (!(index
= emfdc_create_palette( emf
, palette
))) return 0;
755 GDI_hdc_using_object( palette
, dc_attr_handle( dc_attr
), emfdc_delete_object
);
758 emr
.emr
.iType
= EMR_SELECTPALETTE
;
759 emr
.emr
.nSize
= sizeof(emr
);
761 return emfdc_record( emf
, &emr
.emr
);
764 BOOL
EMFDC_RealizePalette( DC_ATTR
*dc_attr
)
766 HPALETTE palette
= GetCurrentObject( dc_attr_handle( dc_attr
), OBJ_PAL
);
767 struct emf
*emf
= get_dc_emf( dc_attr
);
768 EMRREALIZEPALETTE emr
;
770 if (palette
== GetStockObject( DEFAULT_PALETTE
))
773 emr
.emr
.iType
= EMR_REALIZEPALETTE
;
774 emr
.emr
.nSize
= sizeof(emr
);
775 return emfdc_record( emf
, &emr
.emr
);
778 BOOL
EMFDC_SelectObject( DC_ATTR
*dc_attr
, HGDIOBJ obj
)
780 switch (gdi_handle_type( obj
))
782 case NTGDI_OBJ_BRUSH
:
783 return emfdc_select_brush( dc_attr
, obj
);
785 return emfdc_select_font( dc_attr
, obj
);
787 case NTGDI_OBJ_EXTPEN
:
788 return emfdc_select_pen( dc_attr
, obj
);
794 /* determine if we can use 16-bit points to store all the input points */
795 static BOOL
can_use_short_points( const POINT
*pts
, UINT count
)
799 for (i
= 0; i
< count
; i
++)
800 if (((pts
[i
].x
+ 0x8000) & ~0xffff) || ((pts
[i
].y
+ 0x8000) & ~0xffff))
805 /* store points in either long or short format; return a pointer to the end of the stored data */
806 static void *store_points( POINTL
*dest
, const POINT
*pts
, UINT count
, BOOL short_points
)
811 POINTS
*dest_short
= (POINTS
*)dest
;
813 for (i
= 0; i
< count
; i
++)
815 dest_short
[i
].x
= pts
[i
].x
;
816 dest_short
[i
].y
= pts
[i
].y
;
818 return dest_short
+ count
;
822 memcpy( dest
, pts
, count
* sizeof(*dest
) );
827 /* compute the bounds of an array of points, optionally including the current position */
828 static void get_points_bounds( RECTL
*bounds
, const POINT
*pts
, UINT count
, DC_ATTR
*dc_attr
)
834 bounds
->left
= bounds
->right
= dc_attr
->cur_pos
.x
;
835 bounds
->top
= bounds
->bottom
= dc_attr
->cur_pos
.y
;
839 bounds
->left
= bounds
->right
= pts
[0].x
;
840 bounds
->top
= bounds
->bottom
= pts
[0].y
;
842 else *bounds
= empty_bounds
;
844 for (i
= 0; i
< count
; i
++)
846 bounds
->left
= min( bounds
->left
, pts
[i
].x
);
847 bounds
->right
= max( bounds
->right
, pts
[i
].x
);
848 bounds
->top
= min( bounds
->top
, pts
[i
].y
);
849 bounds
->bottom
= max( bounds
->bottom
, pts
[i
].y
);
853 /* helper for path stroke and fill functions */
854 static BOOL
emfdrv_stroke_and_fill_path( struct emf
*emf
, INT type
)
856 EMRSTROKEANDFILLPATH emr
;
859 emr
.emr
.iType
= type
;
860 emr
.emr
.nSize
= sizeof(emr
);
861 emr
.rclBounds
= empty_bounds
;
863 if ((region
= NtGdiPathToRegion( dc_attr_handle( emf
->dc_attr
))))
865 NtGdiGetRgnBox( region
, (RECT
*)&emr
.rclBounds
);
866 DeleteObject( region
);
869 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
870 if (!region
) return FALSE
;
871 emfdc_update_bounds( emf
, &emr
.rclBounds
);
875 BOOL
EMFDC_MoveTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
877 struct emf
*emf
= get_dc_emf( dc_attr
);
880 emr
.emr
.iType
= EMR_MOVETOEX
;
881 emr
.emr
.nSize
= sizeof(emr
);
884 return emfdc_record( emf
, &emr
.emr
);
887 BOOL
EMFDC_LineTo( DC_ATTR
*dc_attr
, INT x
, INT y
)
891 emr
.emr
.iType
= EMR_LINETO
;
892 emr
.emr
.nSize
= sizeof(emr
);
895 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
898 BOOL
EMFDC_ArcChordPie( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
,
899 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD type
)
901 struct emf
*emf
= get_dc_emf( dc_attr
);
905 if (left
== right
|| top
== bottom
) return FALSE
;
907 if (left
> right
) { temp
= left
; left
= right
; right
= temp
; }
908 if (top
> bottom
) { temp
= top
; top
= bottom
; bottom
= temp
; }
910 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
916 emr
.emr
.iType
= type
;
917 emr
.emr
.nSize
= sizeof(emr
);
918 emr
.rclBox
.left
= left
;
919 emr
.rclBox
.top
= top
;
920 emr
.rclBox
.right
= right
;
921 emr
.rclBox
.bottom
= bottom
;
922 emr
.ptlStart
.x
= xstart
;
923 emr
.ptlStart
.y
= ystart
;
926 return emfdc_record( emf
, &emr
.emr
);
929 BOOL
EMFDC_AngleArc( DC_ATTR
*dc_attr
, INT x
, INT y
, DWORD radius
, FLOAT start
, FLOAT sweep
)
933 emr
.emr
.iType
= EMR_ANGLEARC
;
934 emr
.emr
.nSize
= sizeof( emr
);
937 emr
.nRadius
= radius
;
938 emr
.eStartAngle
= start
;
939 emr
.eSweepAngle
= sweep
;
940 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
943 BOOL
EMFDC_Ellipse( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
945 struct emf
*emf
= get_dc_emf( dc_attr
);
948 if (left
== right
|| top
== bottom
) return FALSE
;
950 emr
.emr
.iType
= EMR_ELLIPSE
;
951 emr
.emr
.nSize
= sizeof(emr
);
952 emr
.rclBox
.left
= min( left
, right
);
953 emr
.rclBox
.top
= min( top
, bottom
);
954 emr
.rclBox
.right
= max( left
, right
);
955 emr
.rclBox
.bottom
= max( top
, bottom
);
956 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
961 return emfdc_record( emf
, &emr
.emr
);
964 BOOL
EMFDC_Rectangle( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
966 struct emf
*emf
= get_dc_emf( dc_attr
);
969 if(left
== right
|| top
== bottom
) return FALSE
;
971 emr
.emr
.iType
= EMR_RECTANGLE
;
972 emr
.emr
.nSize
= sizeof(emr
);
973 emr
.rclBox
.left
= min( left
, right
);
974 emr
.rclBox
.top
= min( top
, bottom
);
975 emr
.rclBox
.right
= max( left
, right
);
976 emr
.rclBox
.bottom
= max( top
, bottom
);
977 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
982 return emfdc_record( emf
, &emr
.emr
);
985 BOOL
EMFDC_RoundRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
,
986 INT bottom
, INT ell_width
, INT ell_height
)
988 struct emf
*emf
= get_dc_emf( dc_attr
);
991 if (left
== right
|| top
== bottom
) return FALSE
;
993 emr
.emr
.iType
= EMR_ROUNDRECT
;
994 emr
.emr
.nSize
= sizeof(emr
);
995 emr
.rclBox
.left
= min( left
, right
);
996 emr
.rclBox
.top
= min( top
, bottom
);
997 emr
.rclBox
.right
= max( left
, right
);
998 emr
.rclBox
.bottom
= max( top
, bottom
);
999 emr
.szlCorner
.cx
= ell_width
;
1000 emr
.szlCorner
.cy
= ell_height
;
1001 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1004 emr
.rclBox
.bottom
--;
1006 return emfdc_record( emf
, &emr
.emr
);
1009 BOOL
EMFDC_SetPixel( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
)
1013 emr
.emr
.iType
= EMR_SETPIXELV
;
1014 emr
.emr
.nSize
= sizeof(emr
);
1017 emr
.crColor
= color
;
1018 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
1021 static BOOL
emfdc_polylinegon( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
, DWORD type
)
1023 struct emf
*emf
= get_dc_emf( dc_attr
);
1026 BOOL ret
, use_small_emr
= can_use_short_points( points
, count
);
1028 size
= use_small_emr
? offsetof( EMRPOLYLINE16
, apts
[count
] ) : offsetof( EMRPOLYLINE
, aptl
[count
] );
1030 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1031 emr
->emr
.iType
= use_small_emr
? type
+ EMR_POLYLINE16
- EMR_POLYLINE
: type
;
1032 emr
->emr
.nSize
= size
;
1035 store_points( emr
->aptl
, points
, count
, use_small_emr
);
1038 get_points_bounds( &emr
->rclBounds
, points
, count
,
1039 (type
== EMR_POLYBEZIERTO
|| type
== EMR_POLYLINETO
) ? dc_attr
: 0 );
1041 emr
->rclBounds
= empty_bounds
;
1043 ret
= emfdc_record( emf
, &emr
->emr
);
1044 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1045 HeapFree( GetProcessHeap(), 0, emr
);
1049 BOOL
EMFDC_Polyline( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1051 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINE
);
1054 BOOL
EMFDC_PolylineTo( DC_ATTR
*dc_attr
, const POINT
*points
, INT count
)
1056 return emfdc_polylinegon( dc_attr
, points
, count
, EMR_POLYLINETO
);
1059 BOOL
EMFDC_Polygon( DC_ATTR
*dc_attr
, const POINT
*pt
, INT count
)
1061 if(count
< 2) return FALSE
;
1062 return emfdc_polylinegon( dc_attr
, pt
, count
, EMR_POLYGON
);
1065 BOOL
EMFDC_PolyBezier( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1067 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIER
);
1070 BOOL
EMFDC_PolyBezierTo( DC_ATTR
*dc_attr
, const POINT
*pts
, DWORD count
)
1072 return emfdc_polylinegon( dc_attr
, pts
, count
, EMR_POLYBEZIERTO
);
1075 static BOOL
emfdc_poly_polylinegon( struct emf
*emf
, const POINT
*pt
, const INT
*counts
,
1076 UINT polys
, DWORD type
)
1078 EMRPOLYPOLYLINE
*emr
;
1079 DWORD cptl
= 0, poly
, size
;
1080 BOOL ret
, use_small_emr
, bounds_valid
= TRUE
;
1082 for(poly
= 0; poly
< polys
; poly
++) {
1083 cptl
+= counts
[poly
];
1084 if(counts
[poly
] < 2) bounds_valid
= FALSE
;
1086 if(!cptl
) bounds_valid
= FALSE
;
1087 use_small_emr
= can_use_short_points( pt
, cptl
);
1089 size
= FIELD_OFFSET(EMRPOLYPOLYLINE
, aPolyCounts
[polys
]);
1091 size
+= cptl
* sizeof(POINTS
);
1093 size
+= cptl
* sizeof(POINTL
);
1095 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1097 emr
->emr
.iType
= type
;
1098 if(use_small_emr
) emr
->emr
.iType
+= EMR_POLYPOLYLINE16
- EMR_POLYPOLYLINE
;
1100 emr
->emr
.nSize
= size
;
1101 if(bounds_valid
&& !emf
->path
)
1102 get_points_bounds( &emr
->rclBounds
, pt
, cptl
, 0 );
1104 emr
->rclBounds
= empty_bounds
;
1105 emr
->nPolys
= polys
;
1110 memcpy( emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
) );
1111 store_points( (POINTL
*)(emr
->aPolyCounts
+ polys
), pt
, cptl
, use_small_emr
);
1114 ret
= emfdc_record( emf
, &emr
->emr
);
1115 if(ret
&& !bounds_valid
)
1118 SetLastError( ERROR_INVALID_PARAMETER
);
1120 if(ret
&& !emf
->path
)
1121 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1122 HeapFree( GetProcessHeap(), 0, emr
);
1126 BOOL
EMFDC_PolyPolyline( DC_ATTR
*dc_attr
, const POINT
*pt
, const DWORD
*counts
, DWORD polys
)
1128 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, (const INT
*)counts
, polys
, EMR_POLYPOLYLINE
);
1131 BOOL
EMFDC_PolyPolygon( DC_ATTR
*dc_attr
, const POINT
*pt
, const INT
*counts
, UINT polys
)
1133 return emfdc_poly_polylinegon( get_dc_emf( dc_attr
), pt
, counts
, polys
, EMR_POLYPOLYGON
);
1136 BOOL
EMFDC_PolyDraw( DC_ATTR
*dc_attr
, const POINT
*pts
, const BYTE
*types
, DWORD count
)
1138 struct emf
*emf
= get_dc_emf( dc_attr
);
1142 BOOL use_small_emr
= can_use_short_points( pts
, count
);
1145 size
= use_small_emr
? offsetof( EMRPOLYDRAW16
, apts
[count
] )
1146 : offsetof( EMRPOLYDRAW
, aptl
[count
] );
1147 size
+= (count
+ 3) & ~3;
1149 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
1151 emr
->emr
.iType
= use_small_emr
? EMR_POLYDRAW16
: EMR_POLYDRAW
;
1152 emr
->emr
.nSize
= size
;
1155 types_dest
= store_points( emr
->aptl
, pts
, count
, use_small_emr
);
1156 memcpy( types_dest
, types
, count
);
1157 if (count
& 3) memset( types_dest
+ count
, 0, 4 - (count
& 3) );
1160 get_points_bounds( &emr
->rclBounds
, pts
, count
, 0 );
1162 emr
->rclBounds
= empty_bounds
;
1164 ret
= emfdc_record( emf
, &emr
->emr
);
1165 if (ret
&& !emf
->path
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1166 HeapFree( GetProcessHeap(), 0, emr
);
1170 INT
EMFDC_ExtEscape( DC_ATTR
*dc_attr
, INT escape
, INT input_size
, const char *input
,
1171 INT output_size
, char *output
)
1182 if (escape
== QUERYESCSUPPORT
) return 0;
1184 size
= FIELD_OFFSET( struct EMREXTESCAPE
, data
[input_size
] );
1185 size
= (size
+ 3) & ~3;
1186 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return 0;
1188 emr
->emr
.iType
= EMR_EXTESCAPE
;
1189 emr
->emr
.nSize
= size
;
1190 emr
->escape
= escape
;
1191 emr
->size
= input_size
;
1192 memcpy(emr
->data
, input
, input_size
);
1193 emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1194 HeapFree( GetProcessHeap(), 0, emr
);
1195 if (output_size
&& output
) return 0;
1197 if (escape
== PASSTHROUGH
|| escape
== POSTSCRIPT_PASSTHROUGH
)
1198 input_size
-= sizeof(WORD
);
1199 return input_size
? input_size
: 1;
1202 BOOL
EMFDC_ExtFloodFill( DC_ATTR
*dc_attr
, INT x
, INT y
, COLORREF color
, UINT fill_type
)
1204 EMREXTFLOODFILL emr
;
1206 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
1207 emr
.emr
.nSize
= sizeof(emr
);
1210 emr
.crColor
= color
;
1211 emr
.iMode
= fill_type
;
1212 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
1215 BOOL
EMFDC_FillRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
)
1217 struct emf
*emf
= get_dc_emf( dc_attr
);
1219 DWORD size
, rgnsize
, index
;
1222 if (!(index
= emfdc_create_brush( emf
, hbrush
))) return FALSE
;
1224 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1225 size
= rgnsize
+ offsetof(EMRFILLRGN
,RgnData
);
1226 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1228 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1230 emr
->emr
.iType
= EMR_FILLRGN
;
1231 emr
->emr
.nSize
= size
;
1232 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1233 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1234 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1235 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1236 emr
->cbRgnData
= rgnsize
;
1237 emr
->ihBrush
= index
;
1239 ret
= emfdc_record( emf
, &emr
->emr
);
1240 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1241 HeapFree( GetProcessHeap(), 0, emr
);
1245 BOOL
EMFDC_FrameRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
1247 struct emf
*emf
= get_dc_emf( dc_attr
);
1249 DWORD size
, rgnsize
, index
;
1252 index
= emfdc_create_brush( emf
, hbrush
);
1253 if(!index
) return FALSE
;
1255 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1256 size
= rgnsize
+ offsetof(EMRFRAMERGN
,RgnData
);
1257 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1259 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1261 emr
->emr
.iType
= EMR_FRAMERGN
;
1262 emr
->emr
.nSize
= size
;
1263 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1264 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1265 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1266 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1267 emr
->cbRgnData
= rgnsize
;
1268 emr
->ihBrush
= index
;
1269 emr
->szlStroke
.cx
= width
;
1270 emr
->szlStroke
.cy
= height
;
1272 ret
= emfdc_record( emf
, &emr
->emr
);
1273 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1274 HeapFree( GetProcessHeap(), 0, emr
);
1278 static BOOL
emfdc_paint_invert_region( struct emf
*emf
, HRGN hrgn
, DWORD iType
)
1281 DWORD size
, rgnsize
;
1284 rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
1285 size
= rgnsize
+ offsetof(EMRINVERTRGN
,RgnData
);
1286 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1288 NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
1290 emr
->emr
.iType
= iType
;
1291 emr
->emr
.nSize
= size
;
1292 emr
->rclBounds
.left
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.left
;
1293 emr
->rclBounds
.top
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.top
;
1294 emr
->rclBounds
.right
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.right
- 1;
1295 emr
->rclBounds
.bottom
= ((RGNDATA
*)&emr
->RgnData
)->rdh
.rcBound
.bottom
- 1;
1296 emr
->cbRgnData
= rgnsize
;
1298 ret
= emfdc_record( emf
, &emr
->emr
);
1299 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1300 HeapFree( GetProcessHeap(), 0, emr
);
1304 BOOL
EMFDC_PaintRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1306 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_PAINTRGN
);
1309 BOOL
EMFDC_InvertRgn( DC_ATTR
*dc_attr
, HRGN hrgn
)
1311 return emfdc_paint_invert_region( get_dc_emf( dc_attr
), hrgn
, EMR_INVERTRGN
);
1314 BOOL
EMFDC_ExtTextOut( DC_ATTR
*dc_attr
, INT x
, INT y
, UINT flags
, const RECT
*rect
,
1315 const WCHAR
*str
, UINT count
, const INT
*dx
)
1317 struct emf
*emf
= get_dc_emf( dc_attr
);
1318 HDC hdc
= dc_attr_handle( dc_attr
);
1319 FLOAT ex_scale
, ey_scale
;
1320 EMREXTTEXTOUTW
*emr
;
1321 int text_height
= 0;
1327 size
= sizeof(*emr
) + ((count
+1) & ~1) * sizeof(WCHAR
) + count
* sizeof(INT
);
1329 TRACE( "%s %s count %d size = %ld\n", debugstr_wn(str
, count
),
1330 wine_dbgstr_rect(rect
), count
, size
);
1331 emr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
1333 if (dc_attr
->graphics_mode
== GM_COMPATIBLE
)
1335 HDC hdc
= dc_attr_handle( dc_attr
);
1336 const INT horzSize
= GetDeviceCaps( hdc
, HORZSIZE
);
1337 const INT horzRes
= GetDeviceCaps( hdc
, HORZRES
);
1338 const INT vertSize
= GetDeviceCaps( hdc
, VERTSIZE
);
1339 const INT vertRes
= GetDeviceCaps( hdc
, VERTRES
);
1340 SIZE wndext
, vportext
;
1342 GetViewportExtEx( hdc
, &vportext
);
1343 GetWindowExtEx( hdc
, &wndext
);
1344 ex_scale
= 100.0 * ((FLOAT
)horzSize
/ (FLOAT
)horzRes
) /
1345 ((FLOAT
)wndext
.cx
/ (FLOAT
)vportext
.cx
);
1346 ey_scale
= 100.0 * ((FLOAT
)vertSize
/ (FLOAT
)vertRes
) /
1347 ((FLOAT
)wndext
.cy
/ (FLOAT
)vportext
.cy
);
1355 emr
->emr
.iType
= EMR_EXTTEXTOUTW
;
1356 emr
->emr
.nSize
= size
;
1357 emr
->iGraphicsMode
= dc_attr
->graphics_mode
;
1358 emr
->exScale
= ex_scale
;
1359 emr
->eyScale
= ey_scale
;
1360 emr
->emrtext
.ptlReference
.x
= x
;
1361 emr
->emrtext
.ptlReference
.y
= y
;
1362 emr
->emrtext
.nChars
= count
;
1363 emr
->emrtext
.offString
= sizeof(*emr
);
1364 memcpy( (char*)emr
+ emr
->emrtext
.offString
, str
, count
* sizeof(WCHAR
) );
1365 emr
->emrtext
.fOptions
= flags
;
1368 emr
->emrtext
.rcl
.left
= emr
->emrtext
.rcl
.top
= 0;
1369 emr
->emrtext
.rcl
.right
= emr
->emrtext
.rcl
.bottom
= -1;
1373 emr
->emrtext
.rcl
.left
= rect
->left
;
1374 emr
->emrtext
.rcl
.top
= rect
->top
;
1375 emr
->emrtext
.rcl
.right
= rect
->right
;
1376 emr
->emrtext
.rcl
.bottom
= rect
->bottom
;
1379 emr
->emrtext
.offDx
= emr
->emrtext
.offString
+ ((count
+1) & ~1) * sizeof(WCHAR
);
1384 memcpy( (char*)emr
+ emr
->emrtext
.offDx
, dx
, count
* sizeof(INT
) );
1385 for (i
= 0; i
< count
; i
++) text_width
+= dx
[i
];
1386 if (GetTextExtentPoint32W( hdc
, str
, count
, &str_size
))
1387 text_height
= str_size
.cy
;
1392 INT
*emf_dx
= (INT
*)((char*)emr
+ emr
->emrtext
.offDx
);
1394 for (i
= 0; i
< count
; i
++)
1396 if (GetTextExtentPoint32W( hdc
, str
+ i
, 1, &charSize
))
1398 emf_dx
[i
] = charSize
.cx
;
1399 text_width
+= charSize
.cx
;
1400 text_height
= max( text_height
, charSize
.cy
);
1407 emr
->rclBounds
.left
= emr
->rclBounds
.top
= 0;
1408 emr
->rclBounds
.right
= emr
->rclBounds
.bottom
= -1;
1412 /* FIXME: handle font escapement */
1413 switch (dc_attr
->text_align
& (TA_LEFT
| TA_RIGHT
| TA_CENTER
))
1416 emr
->rclBounds
.left
= x
- (text_width
/ 2) - 1;
1417 emr
->rclBounds
.right
= x
+ (text_width
/ 2) + 1;
1421 emr
->rclBounds
.left
= x
- text_width
- 1;
1422 emr
->rclBounds
.right
= x
;
1425 default: /* TA_LEFT */
1426 emr
->rclBounds
.left
= x
;
1427 emr
->rclBounds
.right
= x
+ text_width
+ 1;
1430 switch (dc_attr
->text_align
& (TA_TOP
| TA_BOTTOM
| TA_BASELINE
))
1433 if (!GetTextMetricsW( hdc
, &tm
)) tm
.tmDescent
= 0;
1434 /* Play safe here... it's better to have a bounding box */
1435 /* that is too big than too small. */
1436 emr
->rclBounds
.top
= y
- text_height
- 1;
1437 emr
->rclBounds
.bottom
= y
+ tm
.tmDescent
+ 1;
1441 emr
->rclBounds
.top
= y
- text_height
- 1;
1442 emr
->rclBounds
.bottom
= y
;
1445 default: /* TA_TOP */
1446 emr
->rclBounds
.top
= y
;
1447 emr
->rclBounds
.bottom
= y
+ text_height
+ 1;
1449 emfdc_update_bounds( emf
, &emr
->rclBounds
);
1452 ret
= emfdc_record( emf
, &emr
->emr
);
1453 HeapFree( GetProcessHeap(), 0, emr
);
1457 BOOL
EMFDC_GradientFill( DC_ATTR
*dc_attr
, TRIVERTEX
*vert_array
, ULONG nvert
,
1458 void *grad_array
, ULONG ngrad
, ULONG mode
)
1460 EMRGRADIENTFILL
*emr
;
1461 ULONG i
, pt
, size
, num_pts
= ngrad
* (mode
== GRADIENT_FILL_TRIANGLE
? 3 : 2);
1462 const ULONG
*pts
= (const ULONG
*)grad_array
;
1465 size
= FIELD_OFFSET(EMRGRADIENTFILL
, Ver
[nvert
]) + num_pts
* sizeof(pts
[0]);
1467 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
1468 if (!emr
) return FALSE
;
1470 for (i
= 0; i
< num_pts
; i
++)
1476 emr
->rclBounds
.left
= emr
->rclBounds
.right
= vert_array
[pt
].x
;
1477 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1481 if (vert_array
[pt
].x
< emr
->rclBounds
.left
)
1482 emr
->rclBounds
.left
= vert_array
[pt
].x
;
1483 else if (vert_array
[pt
].x
> emr
->rclBounds
.right
)
1484 emr
->rclBounds
.right
= vert_array
[pt
].x
;
1485 if (vert_array
[pt
].y
< emr
->rclBounds
.top
)
1486 emr
->rclBounds
.top
= vert_array
[pt
].y
;
1487 else if (vert_array
[pt
].y
> emr
->rclBounds
.bottom
)
1488 emr
->rclBounds
.bottom
= vert_array
[pt
].y
;
1491 emr
->rclBounds
.right
--;
1492 emr
->rclBounds
.bottom
--;
1494 emr
->emr
.iType
= EMR_GRADIENTFILL
;
1495 emr
->emr
.nSize
= size
;
1499 memcpy( emr
->Ver
, vert_array
, nvert
* sizeof(vert_array
[0]) );
1500 memcpy( emr
->Ver
+ nvert
, pts
, num_pts
* sizeof(pts
[0]) );
1502 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1503 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1504 HeapFree( GetProcessHeap(), 0, emr
);
1508 BOOL
EMFDC_FillPath( DC_ATTR
*dc_attr
)
1510 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_FILLPATH
);
1513 BOOL
EMFDC_StrokeAndFillPath( DC_ATTR
*dc_attr
)
1515 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEANDFILLPATH
);
1518 BOOL
EMFDC_StrokePath( DC_ATTR
*dc_attr
)
1520 return emfdrv_stroke_and_fill_path( get_dc_emf( dc_attr
), EMR_STROKEPATH
);
1523 /* Generate an EMRBITBLT, EMRSTRETCHBLT or EMRALPHABLEND record depending on the type parameter */
1524 static BOOL
emfdrv_stretchblt( struct emf
*emf
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1525 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1526 DWORD rop
, DWORD type
)
1528 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1529 UINT bmi_size
, emr_size
, size
;
1530 HBITMAP bitmap
, blit_bitmap
= NULL
;
1531 EMRBITBLT
*emr
= NULL
;
1536 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1539 blit_bitmap
= bitmap
;
1540 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1542 /* EMRSTRETCHBLT and EMRALPHABLEND have the same structure */
1543 emr_size
= type
== EMR_BITBLT
? sizeof(EMRBITBLT
) : sizeof(EMRSTRETCHBLT
);
1544 size
= emr_size
+ bmi_size
+ src_info
.bmiHeader
.biSizeImage
;
1546 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1548 emr
->emr
.iType
= type
;
1549 emr
->emr
.nSize
= size
;
1550 emr
->rclBounds
.left
= x_dst
;
1551 emr
->rclBounds
.top
= y_dst
;
1552 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1553 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1556 emr
->cxDest
= width_dst
;
1557 emr
->cyDest
= height_dst
;
1560 if (type
!= EMR_BITBLT
)
1562 EMRSTRETCHBLT
*emr_stretchblt
= (EMRSTRETCHBLT
*)emr
;
1563 emr_stretchblt
->cxSrc
= width_src
;
1564 emr_stretchblt
->cySrc
= height_src
;
1567 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1568 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1569 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1570 emr
->offBmiSrc
= emr_size
;
1571 emr
->cbBmiSrc
= bmi_size
;
1572 emr
->offBitsSrc
= emr_size
+ bmi_size
;
1573 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1575 bmi
= (BITMAPINFO
*)((BYTE
*)emr
+ emr
->offBmiSrc
);
1576 bmi
->bmiHeader
= src_info
.bmiHeader
;
1577 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1578 (BYTE
*)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1581 ret
= emfdc_record( emf
, (EMR
*)emr
);
1582 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1586 HeapFree( GetProcessHeap(), 0, emr
);
1587 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1588 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1592 BOOL
EMFDC_AlphaBlend( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1593 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1594 BLENDFUNCTION blend_function
)
1596 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
, hdc_src
,
1597 x_src
, y_src
, width_src
, height_src
, *(DWORD
*)&blend_function
,
1601 BOOL
EMFDC_PatBlt( DC_ATTR
*dc_attr
, INT left
, INT top
, INT width
, INT height
, DWORD rop
)
1603 struct emf
*emf
= get_dc_emf( dc_attr
);
1607 emr
.emr
.iType
= EMR_BITBLT
;
1608 emr
.emr
.nSize
= sizeof(emr
);
1609 emr
.rclBounds
.left
= left
;
1610 emr
.rclBounds
.top
= top
;
1611 emr
.rclBounds
.right
= left
+ width
- 1;
1612 emr
.rclBounds
.bottom
= top
+ height
- 1;
1616 emr
.cyDest
= height
;
1620 emr
.xformSrc
.eM11
= 1.0;
1621 emr
.xformSrc
.eM12
= 0.0;
1622 emr
.xformSrc
.eM21
= 0.0;
1623 emr
.xformSrc
.eM22
= 1.0;
1624 emr
.xformSrc
.eDx
= 0.0;
1625 emr
.xformSrc
.eDy
= 0.0;
1626 emr
.crBkColorSrc
= 0;
1633 ret
= emfdc_record( emf
, &emr
.emr
);
1634 if (ret
) emfdc_update_bounds( emf
, &emr
.rclBounds
);
1638 static inline BOOL
rop_uses_src( DWORD rop
)
1640 return ((rop
>> 2) & 0x330000) != (rop
& 0x330000);
1643 BOOL
EMFDC_BitBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width
, INT height
,
1644 HDC hdc_src
, INT x_src
, INT y_src
, DWORD rop
)
1646 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width
, height
, rop
);
1647 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width
, height
,
1648 hdc_src
, x_src
, y_src
, width
, height
, rop
, EMR_BITBLT
);
1651 BOOL
EMFDC_StretchBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1652 HDC hdc_src
, INT x_src
, INT y_src
, INT width_src
, INT height_src
,
1655 if (!rop_uses_src( rop
)) return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1656 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1657 hdc_src
, x_src
, y_src
, width_src
,
1658 height_src
, rop
, EMR_STRETCHBLT
);
1661 BOOL
EMFDC_TransparentBlt( DC_ATTR
*dc_attr
, int x_dst
, int y_dst
, int width_dst
, int height_dst
,
1662 HDC hdc_src
, int x_src
, int y_src
, int width_src
, int height_src
,
1665 return emfdrv_stretchblt( get_dc_emf( dc_attr
), x_dst
, y_dst
, width_dst
, height_dst
,
1666 hdc_src
, x_src
, y_src
, width_src
,
1667 height_src
, color
, EMR_TRANSPARENTBLT
);
1670 BOOL
EMFDC_MaskBlt( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1671 HDC hdc_src
, INT x_src
, INT y_src
, HBITMAP mask
,
1672 INT x_mask
, INT y_mask
, DWORD rop
)
1674 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1675 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1676 struct emf
*emf
= get_dc_emf( dc_attr
);
1677 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1678 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1679 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1680 UINT bmi_size
, size
, mask_info_size
= 0;
1681 EMRMASKBLT
*emr
= NULL
;
1683 HDC blit_dc
, mask_dc
= NULL
;
1686 if (!rop_uses_src( rop
))
1687 return EMFDC_PatBlt( dc_attr
, x_dst
, y_dst
, width_dst
, height_dst
, rop
);
1689 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1691 blit_bitmap
= bitmap
;
1692 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1698 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1699 if (mask_info
.bmiHeader
.biBitCount
== 1)
1700 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1702 else mask_info
.bmiHeader
.biSizeImage
= 0;
1704 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1705 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1707 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1709 emr
->emr
.iType
= EMR_MASKBLT
;
1710 emr
->emr
.nSize
= size
;
1711 emr
->rclBounds
.left
= x_dst
;
1712 emr
->rclBounds
.top
= y_dst
;
1713 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1714 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1717 emr
->cxDest
= width_dst
;
1718 emr
->cyDest
= height_dst
;
1722 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1723 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1724 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1725 emr
->offBmiSrc
= sizeof(*emr
);
1726 emr
->cbBmiSrc
= bmi_size
;
1727 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1728 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1729 emr
->xMask
= x_mask
;
1730 emr
->yMask
= y_mask
;
1731 emr
->iUsageMask
= DIB_PAL_INDICES
;
1732 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1733 emr
->cbBmiMask
= mask_info_size
;
1734 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1735 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1737 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1738 bmi
->bmiHeader
= src_info
.bmiHeader
;
1739 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1740 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1745 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1746 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1747 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1748 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1753 ret
= emfdc_record( emf
, (EMR
*)emr
);
1754 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1758 HeapFree( GetProcessHeap(), 0, emr
);
1759 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1760 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1761 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1762 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1766 BOOL
EMFDC_PlgBlt( DC_ATTR
*dc_attr
, const POINT
*points
, HDC hdc_src
, INT x_src
, INT y_src
,
1767 INT width
, INT height
, HBITMAP mask
, INT x_mask
, INT y_mask
)
1769 unsigned char mask_info_buffer
[FIELD_OFFSET(BITMAPINFO
, bmiColors
[256])];
1770 BITMAPINFO
*mask_bits_info
= (BITMAPINFO
*)mask_info_buffer
;
1771 struct emf
*emf
= get_dc_emf( dc_attr
);
1772 BITMAPINFO mask_info
= {{ sizeof( mask_info
.bmiHeader
) }};
1773 BITMAPINFO src_info
= {{ sizeof( src_info
.bmiHeader
) }};
1774 HBITMAP bitmap
, blit_bitmap
= NULL
, mask_bitmap
= NULL
;
1775 UINT bmi_size
, size
, mask_info_size
= 0;
1776 EMRPLGBLT
*emr
= NULL
;
1778 HDC blit_dc
, mask_dc
= NULL
;
1779 int x_min
, y_min
, x_max
, y_max
, i
;
1782 if (!(bitmap
= GetCurrentObject( hdc_src
, OBJ_BITMAP
))) return FALSE
;
1785 blit_bitmap
= bitmap
;
1786 if (!(bmi_size
= get_bitmap_info( &blit_dc
, &blit_bitmap
, &src_info
))) return FALSE
;
1792 if (!(mask_info_size
= get_bitmap_info( &mask_dc
, &mask_bitmap
, &mask_info
))) goto err
;
1793 if (mask_info
.bmiHeader
.biBitCount
== 1)
1794 mask_info_size
= sizeof(BITMAPINFOHEADER
); /* don't include colors */
1796 else mask_info
.bmiHeader
.biSizeImage
= 0;
1798 size
= sizeof(*emr
) + bmi_size
+ src_info
.bmiHeader
.biSizeImage
+
1799 mask_info_size
+ mask_info
.bmiHeader
.biSizeImage
;
1801 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, size
))) goto err
;
1803 emr
->emr
.iType
= EMR_PLGBLT
;
1804 emr
->emr
.nSize
= size
;
1806 /* FIXME: not exactly what native does */
1807 x_min
= x_max
= points
[1].x
+ points
[2].x
- points
[0].x
;
1808 y_min
= y_max
= points
[1].y
+ points
[2].y
- points
[0].y
;
1809 for (i
= 0; i
< ARRAYSIZE(emr
->aptlDest
); i
++)
1811 x_min
= min( x_min
, points
[i
].x
);
1812 y_min
= min( y_min
, points
[i
].y
);
1813 x_max
= max( x_max
, points
[i
].x
);
1814 y_max
= max( y_min
, points
[i
].y
);
1816 emr
->rclBounds
.left
= x_min
;
1817 emr
->rclBounds
.top
= y_min
;
1818 emr
->rclBounds
.right
= x_max
;
1819 emr
->rclBounds
.bottom
= y_max
;
1820 memcpy( emr
->aptlDest
, points
, sizeof(emr
->aptlDest
) );
1824 emr
->cySrc
= height
;
1825 NtGdiGetTransform( hdc_src
, 0x204, &emr
->xformSrc
);
1826 emr
->crBkColorSrc
= GetBkColor( hdc_src
);
1827 emr
->iUsageSrc
= DIB_RGB_COLORS
;
1828 emr
->offBmiSrc
= sizeof(*emr
);
1829 emr
->cbBmiSrc
= bmi_size
;
1830 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1831 emr
->cbBitsSrc
= src_info
.bmiHeader
.biSizeImage
;
1832 emr
->xMask
= x_mask
;
1833 emr
->yMask
= y_mask
;
1834 emr
->iUsageMask
= DIB_PAL_INDICES
;
1835 emr
->offBmiMask
= mask_info_size
? emr
->offBitsSrc
+ emr
->cbBitsSrc
: 0;
1836 emr
->cbBmiMask
= mask_info_size
;
1837 emr
->offBitsMask
= emr
->offBmiMask
+ emr
->cbBmiMask
;
1838 emr
->cbBitsMask
= mask_info
.bmiHeader
.biSizeImage
;
1840 bmi
= (BITMAPINFO
*)((char *)emr
+ emr
->offBmiSrc
);
1841 bmi
->bmiHeader
= src_info
.bmiHeader
;
1842 ret
= GetDIBits( blit_dc
, blit_bitmap
, 0, src_info
.bmiHeader
.biHeight
,
1843 (char *)emr
+ emr
->offBitsSrc
, bmi
, DIB_RGB_COLORS
);
1848 mask_bits_info
->bmiHeader
= mask_info
.bmiHeader
;
1849 ret
= GetDIBits( blit_dc
, mask_bitmap
, 0, mask_info
.bmiHeader
.biHeight
,
1850 (char *)emr
+ emr
->offBitsMask
, mask_bits_info
, DIB_RGB_COLORS
);
1851 if (ret
) memcpy( (char *)emr
+ emr
->offBmiMask
, mask_bits_info
, mask_info_size
);
1856 ret
= emfdc_record( emf
, (EMR
*)emr
);
1857 if (ret
) emfdc_update_bounds( emf
, &emr
->rclBounds
);
1861 HeapFree( GetProcessHeap(), 0, emr
);
1862 if (mask_bitmap
!= mask
) DeleteObject( mask_bitmap
);
1863 if (mask_dc
!= hdc_src
) DeleteObject( mask_dc
);
1864 if (blit_bitmap
!= bitmap
) DeleteObject( blit_bitmap
);
1865 if (blit_dc
!= hdc_src
) DeleteDC( blit_dc
);
1869 BOOL
EMFDC_StretchDIBits( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, INT width_dst
, INT height_dst
,
1870 INT x_src
, INT y_src
, INT width_src
, INT height_src
, const void *bits
,
1871 const BITMAPINFO
*info
, UINT usage
, DWORD rop
)
1873 EMRSTRETCHDIBITS
*emr
;
1875 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1876 BITMAPINFOHEADER bih
;
1879 /* calculate the size of the colour table and the image */
1880 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1881 &bmi_size
, &img_size
)) return 0;
1883 /* check for overflows */
1884 payload_size
= bmi_size
+ img_size
;
1885 if (payload_size
< bmi_size
) return 0;
1887 emr_size
= sizeof (EMRSTRETCHDIBITS
) + payload_size
;
1888 if (emr_size
< sizeof (EMRSTRETCHDIBITS
)) return 0;
1890 /* allocate record */
1891 if (!(emr
= HeapAlloc(GetProcessHeap(), 0, emr_size
))) return 0;
1893 /* write a bitmap info header (with colours) to the record */
1894 bi
= (BITMAPINFO
*)&emr
[1];
1895 bi
->bmiHeader
= bih
;
1896 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1898 /* write bitmap bits to the record */
1899 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1901 /* fill in the EMR header at the front of our piece of memory */
1902 emr
->emr
.iType
= EMR_STRETCHDIBITS
;
1903 emr
->emr
.nSize
= emr_size
;
1907 emr
->cxDest
= width_dst
;
1908 emr
->cyDest
= height_dst
;
1913 emr
->iUsageSrc
= usage
;
1914 emr
->offBmiSrc
= sizeof (EMRSTRETCHDIBITS
);
1915 emr
->cbBmiSrc
= bmi_size
;
1916 emr
->offBitsSrc
= emr
->offBmiSrc
+ bmi_size
;
1917 emr
->cbBitsSrc
= img_size
;
1919 emr
->cxSrc
= width_src
;
1920 emr
->cySrc
= height_src
;
1922 emr
->rclBounds
.left
= x_dst
;
1923 emr
->rclBounds
.top
= y_dst
;
1924 emr
->rclBounds
.right
= x_dst
+ width_dst
- 1;
1925 emr
->rclBounds
.bottom
= y_dst
+ height_dst
- 1;
1927 /* save the record we just created */
1928 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
1929 if (ret
) emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
1930 HeapFree( GetProcessHeap(), 0, emr
);
1934 BOOL
EMFDC_SetDIBitsToDevice( DC_ATTR
*dc_attr
, INT x_dst
, INT y_dst
, DWORD width
, DWORD height
,
1935 INT x_src
, INT y_src
, UINT startscan
, UINT lines
,
1936 const void *bits
, const BITMAPINFO
*info
, UINT usage
)
1938 EMRSETDIBITSTODEVICE
*emr
;
1940 UINT bmi_size
, img_size
, payload_size
, emr_size
;
1941 UINT src_height
, stride
;
1942 BITMAPINFOHEADER bih
;
1945 /* calculate the size of the colour table and the image */
1946 if (!emf_parse_user_bitmapinfo( &bih
, &info
->bmiHeader
, usage
, TRUE
,
1947 &bmi_size
, &img_size
)) return 0;
1949 if (bih
.biHeight
>= 0)
1951 src_height
= (UINT
)bih
.biHeight
;
1952 if (src_height
> y_src
+ height
) src_height
= y_src
+ height
;
1954 if (src_height
< startscan
) lines
= 0;
1955 else if (lines
> src_height
- startscan
) lines
= src_height
- startscan
;
1957 if (!lines
) return 0;
1959 if (bih
.biCompression
== BI_RGB
|| bih
.biCompression
== BI_BITFIELDS
)
1961 /* truncate image and check for overflows */
1962 stride
= get_dib_stride( bih
.biWidth
, bih
.biBitCount
);
1963 img_size
= lines
* stride
;
1964 if (img_size
/ stride
!= lines
) return 0;
1968 /* check for overflows */
1969 payload_size
= bmi_size
+ img_size
;
1970 if (payload_size
< bmi_size
) return 0;
1972 emr_size
= sizeof (EMRSETDIBITSTODEVICE
) + payload_size
;
1973 if (emr_size
< sizeof (EMRSETDIBITSTODEVICE
)) return 0;
1975 /* allocate record */
1976 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, emr_size
))) return FALSE
;
1978 /* write a bitmap info header (with colours) to the record */
1979 bi
= (BITMAPINFO
*)&emr
[1];
1980 bi
->bmiHeader
= bih
;
1981 emf_copy_colours_from_user_bitmapinfo( bi
, info
, usage
);
1983 /* write bitmap bits to the record */
1984 memcpy ( (BYTE
*)&emr
[1] + bmi_size
, bits
, img_size
);
1986 emr
->emr
.iType
= EMR_SETDIBITSTODEVICE
;
1987 emr
->emr
.nSize
= emr_size
;
1988 emr
->rclBounds
.left
= x_dst
;
1989 emr
->rclBounds
.top
= y_dst
;
1990 emr
->rclBounds
.right
= x_dst
+ width
- 1;
1991 emr
->rclBounds
.bottom
= y_dst
+ height
- 1;
1997 emr
->cySrc
= height
;
1998 emr
->offBmiSrc
= sizeof(EMRSETDIBITSTODEVICE
);
1999 emr
->cbBmiSrc
= bmi_size
;
2000 emr
->offBitsSrc
= sizeof(EMRSETDIBITSTODEVICE
) + bmi_size
;
2001 emr
->cbBitsSrc
= img_size
;
2002 emr
->iUsageSrc
= usage
;
2003 emr
->iStartScan
= startscan
;
2004 emr
->cScans
= lines
;
2006 if ((ret
= emfdc_record( get_dc_emf( dc_attr
), (EMR
*)emr
)))
2007 emfdc_update_bounds( get_dc_emf( dc_attr
), &emr
->rclBounds
);
2009 HeapFree( GetProcessHeap(), 0, emr
);
2013 BOOL
EMFDC_SetDCBrushColor( DC_ATTR
*dc_attr
, COLORREF color
)
2015 struct emf
*emf
= get_dc_emf( dc_attr
);
2016 HDC hdc
= dc_attr_handle( dc_attr
);
2017 EMRSELECTOBJECT emr
;
2020 if (GetCurrentObject( hdc
, OBJ_BRUSH
) != GetStockObject( DC_BRUSH
)) return TRUE
;
2022 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2023 if (!(emf
->dc_brush
= CreateSolidBrush( color
))) return FALSE
;
2024 if (!(index
= emfdc_create_brush( emf
, emf
->dc_brush
))) return FALSE
;
2025 GDI_hdc_using_object( emf
->dc_brush
, hdc
, emfdc_delete_object
);
2026 emr
.emr
.iType
= EMR_SELECTOBJECT
;
2027 emr
.emr
.nSize
= sizeof(emr
);
2028 emr
.ihObject
= index
;
2029 return emfdc_record( emf
, &emr
.emr
);
2032 BOOL
EMFDC_SetDCPenColor( DC_ATTR
*dc_attr
, COLORREF color
)
2034 struct emf
*emf
= get_dc_emf( dc_attr
);
2035 HDC hdc
= dc_attr_handle( dc_attr
);
2036 EMRSELECTOBJECT emr
;
2038 LOGPEN logpen
= { PS_SOLID
, { 0, 0 }, color
};
2040 if (GetCurrentObject( hdc
, OBJ_PEN
) != GetStockObject( DC_PEN
)) return TRUE
;
2042 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2043 if (!(emf
->dc_pen
= CreatePenIndirect( &logpen
))) return FALSE
;
2044 if (!(index
= emfdc_create_pen( emf
, emf
->dc_pen
))) return FALSE
;
2045 GDI_hdc_using_object( emf
->dc_pen
, hdc
, emfdc_delete_object
);
2046 emr
.emr
.iType
= EMR_SELECTOBJECT
;
2047 emr
.emr
.nSize
= sizeof(emr
);
2048 emr
.ihObject
= index
;
2049 return emfdc_record( emf
, &emr
.emr
);
2052 BOOL
EMFDC_SaveDC( DC_ATTR
*dc_attr
)
2056 emr
.emr
.iType
= EMR_SAVEDC
;
2057 emr
.emr
.nSize
= sizeof(emr
);
2058 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2061 BOOL
EMFDC_RestoreDC( DC_ATTR
*dc_attr
, INT level
)
2065 if (abs(level
) > dc_attr
->save_level
|| level
== 0) return FALSE
;
2067 emr
.emr
.iType
= EMR_RESTOREDC
;
2068 emr
.emr
.nSize
= sizeof(emr
);
2070 emr
.iRelative
= level
;
2072 emr
.iRelative
= level
- dc_attr
->save_level
- 1;
2073 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2076 BOOL
EMFDC_SetTextAlign( DC_ATTR
*dc_attr
, UINT align
)
2078 EMRSETTEXTALIGN emr
;
2080 emr
.emr
.iType
= EMR_SETTEXTALIGN
;
2081 emr
.emr
.nSize
= sizeof(emr
);
2083 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2086 BOOL
EMFDC_SetTextJustification( DC_ATTR
*dc_attr
, INT extra
, INT breaks
)
2088 EMRSETTEXTJUSTIFICATION emr
;
2090 emr
.emr
.iType
= EMR_SETTEXTJUSTIFICATION
;
2091 emr
.emr
.nSize
= sizeof(emr
);
2092 emr
.nBreakExtra
= extra
;
2093 emr
.nBreakCount
= breaks
;
2094 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2097 BOOL
EMFDC_SetBkMode( DC_ATTR
*dc_attr
, INT mode
)
2101 emr
.emr
.iType
= EMR_SETBKMODE
;
2102 emr
.emr
.nSize
= sizeof(emr
);
2104 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2107 BOOL
EMFDC_SetBkColor( DC_ATTR
*dc_attr
, COLORREF color
)
2111 emr
.emr
.iType
= EMR_SETBKCOLOR
;
2112 emr
.emr
.nSize
= sizeof(emr
);
2113 emr
.crColor
= color
;
2114 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2118 BOOL
EMFDC_SetTextColor( DC_ATTR
*dc_attr
, COLORREF color
)
2120 EMRSETTEXTCOLOR emr
;
2122 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
2123 emr
.emr
.nSize
= sizeof(emr
);
2124 emr
.crColor
= color
;
2125 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2128 BOOL
EMFDC_SetROP2( DC_ATTR
*dc_attr
, INT rop
)
2132 emr
.emr
.iType
= EMR_SETROP2
;
2133 emr
.emr
.nSize
= sizeof(emr
);
2135 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2138 BOOL
EMFDC_SetPolyFillMode( DC_ATTR
*dc_attr
, INT mode
)
2140 EMRSETPOLYFILLMODE emr
;
2142 emr
.emr
.iType
= EMR_SETPOLYFILLMODE
;
2143 emr
.emr
.nSize
= sizeof(emr
);
2145 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2148 BOOL
EMFDC_SetStretchBltMode( DC_ATTR
*dc_attr
, INT mode
)
2150 EMRSETSTRETCHBLTMODE emr
;
2152 emr
.emr
.iType
= EMR_SETSTRETCHBLTMODE
;
2153 emr
.emr
.nSize
= sizeof(emr
);
2155 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2158 BOOL
EMFDC_SetArcDirection( DC_ATTR
*dc_attr
, INT dir
)
2160 EMRSETARCDIRECTION emr
;
2162 emr
.emr
.iType
= EMR_SETARCDIRECTION
;
2163 emr
.emr
.nSize
= sizeof(emr
);
2164 emr
.iArcDirection
= dir
;
2165 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2168 INT
EMFDC_ExcludeClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2170 EMREXCLUDECLIPRECT emr
;
2172 emr
.emr
.iType
= EMR_EXCLUDECLIPRECT
;
2173 emr
.emr
.nSize
= sizeof(emr
);
2174 emr
.rclClip
.left
= left
;
2175 emr
.rclClip
.top
= top
;
2176 emr
.rclClip
.right
= right
;
2177 emr
.rclClip
.bottom
= bottom
;
2178 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2181 BOOL
EMFDC_IntersectClipRect( DC_ATTR
*dc_attr
, INT left
, INT top
, INT right
, INT bottom
)
2183 EMRINTERSECTCLIPRECT emr
;
2185 emr
.emr
.iType
= EMR_INTERSECTCLIPRECT
;
2186 emr
.emr
.nSize
= sizeof(emr
);
2187 emr
.rclClip
.left
= left
;
2188 emr
.rclClip
.top
= top
;
2189 emr
.rclClip
.right
= right
;
2190 emr
.rclClip
.bottom
= bottom
;
2191 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2194 BOOL
EMFDC_OffsetClipRgn( DC_ATTR
*dc_attr
, INT x
, INT y
)
2196 EMROFFSETCLIPRGN emr
;
2198 emr
.emr
.iType
= EMR_OFFSETCLIPRGN
;
2199 emr
.emr
.nSize
= sizeof(emr
);
2200 emr
.ptlOffset
.x
= x
;
2201 emr
.ptlOffset
.y
= y
;
2202 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2205 BOOL
EMFDC_ExtSelectClipRgn( DC_ATTR
*dc_attr
, HRGN hrgn
, INT mode
)
2207 EMREXTSELECTCLIPRGN
*emr
;
2208 DWORD size
, rgnsize
;
2213 if (mode
!= RGN_COPY
) return ERROR
;
2216 else rgnsize
= NtGdiGetRegionData( hrgn
, 0, NULL
);
2218 size
= rgnsize
+ offsetof(EMREXTSELECTCLIPRGN
,RgnData
);
2219 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
2220 if (rgnsize
) NtGdiGetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
2222 emr
->emr
.iType
= EMR_EXTSELECTCLIPRGN
;
2223 emr
->emr
.nSize
= size
;
2224 emr
->cbRgnData
= rgnsize
;
2227 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2228 HeapFree( GetProcessHeap(), 0, emr
);
2232 BOOL
EMFDC_SetMapMode( DC_ATTR
*dc_attr
, INT mode
)
2236 emr
.emr
.iType
= EMR_SETMAPMODE
;
2237 emr
.emr
.nSize
= sizeof(emr
);
2239 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2242 BOOL
EMFDC_SetViewportExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2244 EMRSETVIEWPORTEXTEX emr
;
2246 emr
.emr
.iType
= EMR_SETVIEWPORTEXTEX
;
2247 emr
.emr
.nSize
= sizeof(emr
);
2248 emr
.szlExtent
.cx
= cx
;
2249 emr
.szlExtent
.cy
= cy
;
2250 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2253 BOOL
EMFDC_SetWindowExtEx( DC_ATTR
*dc_attr
, INT cx
, INT cy
)
2255 EMRSETWINDOWEXTEX emr
;
2257 emr
.emr
.iType
= EMR_SETWINDOWEXTEX
;
2258 emr
.emr
.nSize
= sizeof(emr
);
2259 emr
.szlExtent
.cx
= cx
;
2260 emr
.szlExtent
.cy
= cy
;
2261 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2264 BOOL
EMFDC_SetViewportOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2266 EMRSETVIEWPORTORGEX emr
;
2268 emr
.emr
.iType
= EMR_SETVIEWPORTORGEX
;
2269 emr
.emr
.nSize
= sizeof(emr
);
2270 emr
.ptlOrigin
.x
= x
;
2271 emr
.ptlOrigin
.y
= y
;
2272 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2275 BOOL
EMFDC_SetWindowOrgEx( DC_ATTR
*dc_attr
, INT x
, INT y
)
2277 EMRSETWINDOWORGEX emr
;
2279 emr
.emr
.iType
= EMR_SETWINDOWORGEX
;
2280 emr
.emr
.nSize
= sizeof(emr
);
2281 emr
.ptlOrigin
.x
= x
;
2282 emr
.ptlOrigin
.y
= y
;
2283 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2286 BOOL
EMFDC_ScaleViewportExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2288 EMRSCALEVIEWPORTEXTEX emr
;
2290 emr
.emr
.iType
= EMR_SCALEVIEWPORTEXTEX
;
2291 emr
.emr
.nSize
= sizeof(emr
);
2293 emr
.xDenom
= x_denom
;
2295 emr
.yDenom
= y_denom
;
2296 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2299 BOOL
EMFDC_ScaleWindowExtEx( DC_ATTR
*dc_attr
, INT x_num
, INT x_denom
, INT y_num
, INT y_denom
)
2301 EMRSCALEWINDOWEXTEX emr
;
2303 emr
.emr
.iType
= EMR_SCALEWINDOWEXTEX
;
2304 emr
.emr
.nSize
= sizeof(emr
);
2306 emr
.xDenom
= x_denom
;
2308 emr
.yDenom
= y_denom
;
2309 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2312 BOOL
EMFDC_SetLayout( DC_ATTR
*dc_attr
, DWORD layout
)
2316 emr
.emr
.iType
= EMR_SETLAYOUT
;
2317 emr
.emr
.nSize
= sizeof(emr
);
2319 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2322 BOOL
EMFDC_SetWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
)
2324 EMRSETWORLDTRANSFORM emr
;
2326 emr
.emr
.iType
= EMR_SETWORLDTRANSFORM
;
2327 emr
.emr
.nSize
= sizeof(emr
);
2329 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2332 BOOL
EMFDC_ModifyWorldTransform( DC_ATTR
*dc_attr
, const XFORM
*xform
, DWORD mode
)
2334 EMRMODIFYWORLDTRANSFORM emr
;
2336 emr
.emr
.iType
= EMR_MODIFYWORLDTRANSFORM
;
2337 emr
.emr
.nSize
= sizeof(emr
);
2338 if (mode
== MWT_IDENTITY
)
2340 emr
.xform
.eM11
= 1.0f
;
2341 emr
.xform
.eM12
= 0.0f
;
2342 emr
.xform
.eM21
= 0.0f
;
2343 emr
.xform
.eM22
= 1.0f
;
2344 emr
.xform
.eDx
= 0.0f
;
2345 emr
.xform
.eDy
= 0.0f
;
2352 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2355 BOOL
EMFDC_SetMapperFlags( DC_ATTR
*dc_attr
, DWORD flags
)
2357 EMRSETMAPPERFLAGS emr
;
2359 emr
.emr
.iType
= EMR_SETMAPPERFLAGS
;
2360 emr
.emr
.nSize
= sizeof(emr
);
2361 emr
.dwFlags
= flags
;
2362 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2365 BOOL
EMFDC_AbortPath( DC_ATTR
*dc_attr
)
2367 struct emf
*emf
= get_dc_emf( dc_attr
);
2370 emr
.emr
.iType
= EMR_ABORTPATH
;
2371 emr
.emr
.nSize
= sizeof(emr
);
2374 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2377 BOOL
EMFDC_BeginPath( DC_ATTR
*dc_attr
)
2379 struct emf
*emf
= get_dc_emf( dc_attr
);
2382 emr
.emr
.iType
= EMR_BEGINPATH
;
2383 emr
.emr
.nSize
= sizeof(emr
);
2384 if (!emfdc_record( emf
, &emr
.emr
)) return FALSE
;
2390 BOOL
EMFDC_CloseFigure( DC_ATTR
*dc_attr
)
2394 emr
.emr
.iType
= EMR_CLOSEFIGURE
;
2395 emr
.emr
.nSize
= sizeof(emr
);
2396 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2399 BOOL
EMFDC_EndPath( DC_ATTR
*dc_attr
)
2401 struct emf
*emf
= get_dc_emf( dc_attr
);
2406 emr
.emr
.iType
= EMR_ENDPATH
;
2407 emr
.emr
.nSize
= sizeof(emr
);
2408 return emfdc_record( emf
, &emr
.emr
);
2411 BOOL
EMFDC_FlattenPath( DC_ATTR
*dc_attr
)
2415 emr
.emr
.iType
= EMR_FLATTENPATH
;
2416 emr
.emr
.nSize
= sizeof(emr
);
2417 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2420 BOOL
EMFDC_SelectClipPath( DC_ATTR
*dc_attr
, INT mode
)
2422 EMRSELECTCLIPPATH emr
;
2424 emr
.emr
.iType
= EMR_SELECTCLIPPATH
;
2425 emr
.emr
.nSize
= sizeof(emr
);
2427 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2430 BOOL
EMFDC_WidenPath( DC_ATTR
*dc_attr
)
2434 emr
.emr
.iType
= EMR_WIDENPATH
;
2435 emr
.emr
.nSize
= sizeof(emr
);
2436 return emfdc_record( get_dc_emf( dc_attr
), &emr
.emr
);
2439 void EMFDC_DeleteDC( DC_ATTR
*dc_attr
)
2441 struct emf
*emf
= get_dc_emf( dc_attr
);
2444 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2445 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2446 CloseHandle( emf
->file
);
2447 HeapFree( GetProcessHeap(), 0, emf
->palette
);
2448 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2449 for (index
= 0; index
< emf
->handles_size
; index
++)
2450 if (emf
->handles
[index
])
2451 GDI_hdc_not_using_object( emf
->handles
[index
], dc_attr_handle( emf
->dc_attr
));
2452 HeapFree( GetProcessHeap(), 0, emf
->handles
);
2453 HeapFree( GetProcessHeap(), 0, emf
);
2457 /*******************************************************************
2458 * GdiComment (GDI32.@)
2460 BOOL WINAPI
GdiComment( HDC hdc
, UINT bytes
, const BYTE
*buffer
)
2464 UINT total
, rounded_size
;
2467 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return FALSE
;
2469 rounded_size
= (bytes
+3) & ~3;
2470 total
= offsetof(EMRGDICOMMENT
,Data
) + rounded_size
;
2472 emr
= HeapAlloc(GetProcessHeap(), 0, total
);
2473 emr
->emr
.iType
= EMR_GDICOMMENT
;
2474 emr
->emr
.nSize
= total
;
2475 emr
->cbData
= bytes
;
2476 memset(&emr
->Data
[bytes
], 0, rounded_size
- bytes
);
2477 memcpy(&emr
->Data
[0], buffer
, bytes
);
2479 ret
= emfdc_record( get_dc_emf( dc_attr
), &emr
->emr
);
2481 HeapFree(GetProcessHeap(), 0, emr
);
2486 /**********************************************************************
2487 * CreateEnhMetaFileA (GDI32.@)
2489 HDC WINAPI
CreateEnhMetaFileA( HDC hdc
, const char *filename
, const RECT
*rect
,
2490 const char *description
)
2492 WCHAR
*filenameW
= NULL
;
2493 WCHAR
*descriptionW
= NULL
;
2494 DWORD len1
, len2
, total
;
2499 total
= MultiByteToWideChar( CP_ACP
, 0, filename
, -1, NULL
, 0 );
2500 filenameW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2501 MultiByteToWideChar( CP_ACP
, 0, filename
, -1, filenameW
, total
);
2506 len1
= strlen(description
);
2507 len2
= strlen(description
+ len1
+ 1);
2508 total
= MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, NULL
, 0 );
2509 descriptionW
= HeapAlloc( GetProcessHeap(), 0, total
* sizeof(WCHAR
) );
2510 MultiByteToWideChar( CP_ACP
, 0, description
, len1
+ len2
+ 3, descriptionW
, total
);
2513 ret
= CreateEnhMetaFileW( hdc
, filenameW
, rect
, descriptionW
);
2515 HeapFree( GetProcessHeap(), 0, filenameW
);
2516 HeapFree( GetProcessHeap(), 0, descriptionW
);
2520 static void emf_reset( DC_ATTR
*dc_attr
, const RECT
*rect
)
2522 struct emf
*emf
= get_dc_emf( dc_attr
);
2523 HDC hdc
= dc_attr_handle( dc_attr
);
2526 for (i
= 0; i
< emf
->handles_size
; i
++)
2527 if (emf
->handles
[i
])
2528 GDI_hdc_not_using_object( emf
->handles
[i
], dc_attr_handle( emf
->dc_attr
));
2529 memset( emf
->handles
, 0, emf
->handles_size
* sizeof(emf
->handles
[0]) );
2530 emf
->cur_handles
= 1;
2532 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2534 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2537 emf
->palette_used
= 0;
2539 dc_attr
->emf_bounds
.left
= dc_attr
->emf_bounds
.top
= 0;
2540 dc_attr
->emf_bounds
.right
= dc_attr
->emf_bounds
.bottom
= -1;
2544 emf
->emh
->rclFrame
.left
= rect
->left
;
2545 emf
->emh
->rclFrame
.top
= rect
->top
;
2546 emf
->emh
->rclFrame
.right
= rect
->right
;
2547 emf
->emh
->rclFrame
.bottom
= rect
->bottom
;
2551 /* Set this to {0,0 - -1,-1} and update it at the end */
2552 emf
->emh
->rclFrame
.left
= emf
->emh
->rclFrame
.top
= 0;
2553 emf
->emh
->rclFrame
.right
= emf
->emh
->rclFrame
.bottom
= -1;
2556 emf
->emh
->dSignature
= ENHMETA_SIGNATURE
;
2557 emf
->emh
->nVersion
= 0x10000;
2558 emf
->emh
->nBytes
= emf
->emh
->nSize
;
2559 emf
->emh
->nRecords
= 1;
2560 emf
->emh
->nHandles
= 1;
2561 emf
->emh
->sReserved
= 0; /* According to docs, this is reserved and must be 0 */
2562 emf
->emh
->nPalEntries
= 0;
2564 /* Size in pixels */
2565 emf
->emh
->szlDevice
.cx
= GetDeviceCaps( hdc
, HORZRES
);
2566 emf
->emh
->szlDevice
.cy
= GetDeviceCaps( hdc
, VERTRES
);
2568 /* Size in millimeters */
2569 emf
->emh
->szlMillimeters
.cx
= GetDeviceCaps( hdc
, HORZSIZE
);
2570 emf
->emh
->szlMillimeters
.cy
= GetDeviceCaps( hdc
, VERTSIZE
);
2572 emf
->emh
->cbPixelFormat
= 0;
2573 emf
->emh
->offPixelFormat
= 0;
2574 emf
->emh
->bOpenGL
= 0;
2576 /* Size in micrometers */
2577 emf
->emh
->szlMicrometers
.cx
= emf
->emh
->szlMillimeters
.cx
* 1000;
2578 emf
->emh
->szlMicrometers
.cy
= emf
->emh
->szlMillimeters
.cy
* 1000;
2581 static struct emf
*emf_create( HDC hdc
, const RECT
*rect
, const WCHAR
*description
)
2583 DWORD size
= 0, length
= 0;
2587 if (!(dc_attr
= get_dc_attr( hdc
)) || !(emf
= HeapAlloc( GetProcessHeap(), 0, sizeof(*emf
) )))
2590 if (description
) /* App name\0Title\0\0 */
2592 length
= lstrlenW( description
);
2593 length
+= lstrlenW( description
+ length
+ 1 );
2597 size
= sizeof(ENHMETAHEADER
) + (length
+ 3) / 4 * 4;
2599 if (!(emf
->emh
= HeapAlloc( GetProcessHeap(), 0, size
)) ||
2600 !(emf
->handles
= HeapAlloc( GetProcessHeap(), 0,
2601 HANDLE_LIST_INC
* sizeof(emf
->handles
[0]) )))
2603 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2604 HeapFree( GetProcessHeap(), 0, emf
);
2608 emf
->dc_attr
= dc_attr
;
2609 dc_attr
->emf
= (UINT_PTR
)emf
;
2611 emf
->handles_size
= HANDLE_LIST_INC
;
2614 emf
->palette_size
= 0;
2615 emf
->palette
= NULL
;
2617 emf
->emh
->iType
= EMR_HEADER
;
2618 emf
->emh
->nSize
= size
;
2619 emf
->emh
->nDescription
= length
/ 2;
2620 emf
->emh
->offDescription
= length
? sizeof(ENHMETAHEADER
) : 0;
2622 memcpy( (char *)emf
->emh
+ sizeof(ENHMETAHEADER
), description
, length
);
2624 emf_reset( dc_attr
, rect
);
2628 /**********************************************************************
2629 * CreateEnhMetaFileW (GDI32.@)
2631 HDC WINAPI
CreateEnhMetaFileW( HDC hdc
, const WCHAR
*filename
, const RECT
*rect
,
2632 const WCHAR
*description
)
2638 TRACE( "(%p %s %s %s)\n", hdc
, debugstr_w(filename
), wine_dbgstr_rect(rect
),
2639 debugstr_w(description
) );
2641 if (!(ret
= NtGdiCreateMetafileDC( hdc
))) return 0;
2643 emf
= emf_create( ret
, rect
, description
);
2650 if (filename
) /* disk based metafile */
2652 if ((file
= CreateFileW( filename
, GENERIC_WRITE
| GENERIC_READ
, 0,
2653 NULL
, CREATE_ALWAYS
, 0, 0)) == INVALID_HANDLE_VALUE
)
2661 TRACE( "returning %p\n", ret
);
2665 static BOOL
emf_eof( DC_ATTR
*dc_attr
)
2667 struct emf
*emf
= get_dc_emf( dc_attr
);
2668 UINT size
, palette_size
;
2672 palette_size
= emf
->palette_used
* sizeof(*emf
->palette
);
2673 size
= sizeof(*emr
) + palette_size
;
2674 if (!(emr
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
2676 emr
->emr
.iType
= EMR_EOF
;
2677 emr
->emr
.nSize
= size
;
2678 emr
->nPalEntries
= emf
->palette_used
;
2679 emr
->offPalEntries
= FIELD_OFFSET(EMREOF
, nSizeLast
);
2680 memcpy( (BYTE
*)emr
+ emr
->offPalEntries
, emf
->palette
, palette_size
);
2682 ((DWORD
*)((BYTE
*)emr
+ size
))[-1] = size
;
2683 ret
= emfdc_record( emf
, &emr
->emr
);
2684 HeapFree( GetProcessHeap(), 0, emr
);
2685 if (!ret
) return FALSE
;
2687 emf
->emh
->rclBounds
= dc_attr
->emf_bounds
;
2689 /* Update rclFrame if not initialized in CreateEnhMetaFile */
2690 if (emf
->emh
->rclFrame
.left
> emf
->emh
->rclFrame
.right
)
2692 emf
->emh
->rclFrame
.left
= emf
->emh
->rclBounds
.left
*
2693 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2694 emf
->emh
->rclFrame
.top
= emf
->emh
->rclBounds
.top
*
2695 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2696 emf
->emh
->rclFrame
.right
= emf
->emh
->rclBounds
.right
*
2697 emf
->emh
->szlMillimeters
.cx
* 100 / emf
->emh
->szlDevice
.cx
;
2698 emf
->emh
->rclFrame
.bottom
= emf
->emh
->rclBounds
.bottom
*
2699 emf
->emh
->szlMillimeters
.cy
* 100 / emf
->emh
->szlDevice
.cy
;
2704 /******************************************************************
2705 * CloseEnhMetaFile (GDI32.@)
2707 HENHMETAFILE WINAPI
CloseEnhMetaFile( HDC hdc
)
2714 TRACE("(%p)\n", hdc
);
2716 if (!(dc_attr
= get_dc_attr( hdc
)) || !get_dc_emf( dc_attr
)) return 0;
2717 emf
= get_dc_emf( dc_attr
);
2719 if (dc_attr
->save_level
)
2720 RestoreDC( hdc
, 1 );
2722 if (emf
->dc_brush
) DeleteObject( emf
->dc_brush
);
2724 if (emf
->dc_pen
) DeleteObject( emf
->dc_pen
);
2727 if (!emf_eof( dc_attr
)) return 0;
2729 if (emf
->file
) /* disk based metafile */
2731 if (!WriteFile( emf
->file
, emf
->emh
, emf
->emh
->nBytes
, NULL
, NULL
))
2733 CloseHandle( emf
->file
);
2737 HeapFree( GetProcessHeap(), 0, emf
->emh
);
2738 mapping
= CreateFileMappingA( emf
->file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
2739 TRACE( "mapping = %p\n", mapping
);
2740 emf
->emh
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, 0 );
2741 TRACE( "view = %p\n", emf
->emh
);
2742 CloseHandle( mapping
);
2743 CloseHandle( emf
->file
);
2746 hmf
= EMF_Create_HENHMETAFILE( emf
->emh
, emf
->emh
->nBytes
, emf
->file
!= 0 );
2748 emf
->emh
= NULL
; /* So it won't be deleted */
2753 BOOL
spool_start_doc( DC_ATTR
*dc_attr
, HANDLE hspool
, const DOCINFOW
*doc_info
)
2757 unsigned int dwVersion
;
2758 unsigned int cjSize
;
2759 unsigned int dpszDocName
;
2760 unsigned int dpszOutput
;
2762 size_t size
= sizeof(*header
);
2767 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2769 if (doc_info
->lpszDocName
)
2770 size
+= (wcslen( doc_info
->lpszDocName
) + 1) * sizeof(WCHAR
);
2771 if (doc_info
->lpszOutput
)
2772 size
+= (wcslen( doc_info
->lpszOutput
) + 1) * sizeof(WCHAR
);
2773 header
= HeapAlloc( GetProcessHeap(), 0, size
);
2774 if (!header
) return FALSE
;
2776 header
->dwVersion
= 0x10000;
2777 header
->cjSize
= size
;
2778 p
= (WCHAR
*)(header
+ 1);
2779 if (doc_info
->lpszDocName
)
2781 header
->dpszDocName
= (BYTE
*)p
- (BYTE
*)header
;
2782 wcscpy( p
, doc_info
->lpszDocName
);
2783 p
+= wcslen( doc_info
->lpszDocName
) + 1;
2787 header
->dpszDocName
= 0;
2789 if (doc_info
->lpszOutput
)
2791 header
->dpszOutput
= (BYTE
*)p
- (BYTE
*)header
;
2792 wcscpy( p
, doc_info
->lpszOutput
);
2796 header
->dpszOutput
= 0;
2798 if (!WritePrinter( hspool
, header
, size
, &written
)) written
= 0;
2799 HeapFree( GetProcessHeap(), 0, header
);
2800 if (written
!= size
) return FALSE
;
2802 emf
= emf_create( dc_attr_handle(dc_attr
), NULL
, NULL
);
2803 if (!emf
) return FALSE
;
2807 int spool_start_page( DC_ATTR
*dc_attr
, HANDLE hspool
)
2809 HDC hdc
= dc_attr_handle( dc_attr
);
2813 TRACE( "(%p)\n", dc_attr
);
2815 /* Save current DC state to EMF */
2816 /* FIXME: SetTextJustification if needed */
2817 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_PEN
) );
2818 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_BRUSH
) );
2819 EMFDC_SelectObject( dc_attr
, GetCurrentObject(hdc
, OBJ_FONT
) );
2820 if (GetBkColor( hdc
) != 0xffffff)
2821 EMFDC_SetBkColor( dc_attr
, GetBkColor(hdc
) );
2822 if (GetBkMode( hdc
) != OPAQUE
)
2823 EMFDC_SetBkMode( dc_attr
, GetBkMode(hdc
) );
2824 GetCurrentPositionEx( hdc
, &pos
);
2826 EMFDC_MoveTo( dc_attr
, pos
.x
, pos
.y
);
2827 if (GetMapMode( hdc
) != MM_TEXT
)
2828 EMFDC_SetMapMode( dc_attr
, GetMapMode(hdc
) );
2829 if (GetPolyFillMode( hdc
) != ALTERNATE
)
2830 EMFDC_SetPolyFillMode( dc_attr
, GetPolyFillMode(hdc
) );
2831 if (GetROP2( hdc
) != R2_COPYPEN
)
2832 EMFDC_SetROP2( dc_attr
, GetROP2(hdc
) );
2833 if (GetStretchBltMode( hdc
) != BLACKONWHITE
)
2834 EMFDC_SetStretchBltMode( dc_attr
, GetStretchBltMode(hdc
) );
2835 if (GetTextAlign( hdc
) != (TA_LEFT
| TA_TOP
))
2836 EMFDC_SetTextAlign( dc_attr
, GetTextAlign(hdc
) );
2837 if (GetTextColor( hdc
))
2838 EMFDC_SetTextColor( dc_attr
, GetTextColor(hdc
) );
2839 GetWorldTransform(hdc
, &xform
);
2840 if (xform
.eM11
!= 1 || xform
.eM22
!= 1 || xform
.eM12
|| xform
.eM21
|| xform
.eDx
|| xform
.eDy
)
2841 EMFDC_SetWorldTransform( dc_attr
, &xform
);
2843 return StartPagePrinter( hspool
);
2846 int spool_end_page( DC_ATTR
*dc_attr
, HANDLE hspool
, const DEVMODEW
*devmode
, BOOL write_devmode
)
2851 unsigned int cjSize
;
2855 struct record_hdr hdr
;
2858 struct emf
*emf
= get_dc_emf( dc_attr
);
2861 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2863 if (!emf_eof( dc_attr
)) return 0;
2865 record_hdr
.ulID
= EMRI_METAFILE_DATA
;
2866 record_hdr
.cjSize
= emf
->emh
->nBytes
;
2867 if (!WritePrinter( hspool
, &record_hdr
, sizeof(record_hdr
), &written
)) return 0;
2868 if (!WritePrinter( hspool
, emf
->emh
, emf
->emh
->nBytes
, &written
)) return 0;
2872 record_hdr
.ulID
= EMRI_DEVMODE
;
2873 record_hdr
.cjSize
= devmode
? devmode
->dmSize
+ devmode
->dmDriverExtra
: 0;
2874 if (!WritePrinter( hspool
, &record_hdr
, sizeof(record_hdr
), &written
)) return 0;
2875 if (devmode
&& !WritePrinter( hspool
, (BYTE
*)devmode
,
2876 record_hdr
.cjSize
, &written
)) return 0;
2879 metafile_ext
.hdr
.ulID
= EMRI_METAFILE_EXT
;
2880 metafile_ext
.hdr
.cjSize
= sizeof(metafile_ext
) - sizeof(struct record_hdr
);
2881 metafile_ext
.pos
.QuadPart
= emf
->emh
->nBytes
+ sizeof(record_hdr
);
2883 metafile_ext
.pos
.QuadPart
+= record_hdr
.cjSize
+ sizeof(record_hdr
);
2884 if (!WritePrinter( hspool
, &metafile_ext
, sizeof(metafile_ext
), &written
)) return 0;
2886 emf_reset( dc_attr
, NULL
);
2887 return EndPagePrinter( hspool
);
2890 int spool_abort_doc( DC_ATTR
*dc_attr
, HANDLE hspool
)
2892 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2894 EMFDC_DeleteDC( dc_attr
);
2895 return AbortPrinter( hspool
);
2898 int spool_end_doc( DC_ATTR
*dc_attr
, HANDLE hspool
)
2900 TRACE( "(%p %p)\n", dc_attr
, hspool
);
2902 EMFDC_DeleteDC( dc_attr
);
2903 return EndDocPrinter( hspool
);