include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / gdi32 / metadc.c
blobdbfa311b71165d6eee6f2772a9f63bf8f65a2518
1 /*
2 * Metafile DC functions
4 * Copyright 1999 Huw D M Davies
5 * Copyright 1993, 1994, 1996 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
23 #include <stdarg.h>
25 #include "gdi_private.h"
26 #include "winnls.h"
27 #include "wine/wingdi16.h"
29 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
34 struct metadc
36 HDC hdc;
37 METAHEADER *mh; /* Pointer to metafile header */
38 UINT handles_size, cur_handles;
39 HGDIOBJ *handles;
40 HANDLE hFile; /* Handle for disk based MetaFile */
41 HPEN pen;
42 HBRUSH brush;
43 HFONT font;
46 #define HANDLE_LIST_INC 20
48 struct metadc *get_metadc_ptr( HDC hdc )
50 struct metadc *metafile = get_gdi_client_ptr( hdc, NTGDI_OBJ_METADC );
51 if (!metafile) SetLastError( ERROR_INVALID_HANDLE );
52 return metafile;
55 static BOOL metadc_write_record( struct metadc *metadc, METARECORD *mr, unsigned int rlen )
57 DWORD len, size;
58 METAHEADER *mh;
60 len = metadc->mh->mtSize * sizeof(WORD) + rlen;
61 size = HeapSize( GetProcessHeap(), 0, metadc->mh );
62 if (len > size)
64 size += size / sizeof(WORD) + rlen;
65 mh = HeapReAlloc( GetProcessHeap(), 0, metadc->mh, size );
66 if (!mh) return FALSE;
67 metadc->mh = mh;
69 memcpy( (WORD *)metadc->mh + metadc->mh->mtSize, mr, rlen );
71 metadc->mh->mtSize += rlen / sizeof(WORD);
72 metadc->mh->mtMaxRecord = max( metadc->mh->mtMaxRecord, rlen / sizeof(WORD) );
73 return TRUE;
76 static BOOL metadc_record( HDC hdc, METARECORD *mr, DWORD rlen )
78 struct metadc *metadc;
80 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
81 return metadc_write_record( metadc, mr, rlen );
84 static BOOL metadc_param0( HDC hdc, short func )
86 METARECORD mr;
88 mr.rdSize = FIELD_OFFSET(METARECORD, rdParm[0]) / sizeof(WORD);
89 mr.rdFunction = func;
90 return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
93 static BOOL metadc_param1( HDC hdc, short func, short param )
95 METARECORD mr;
97 mr.rdSize = sizeof(mr) / sizeof(WORD);
98 mr.rdFunction = func;
99 mr.rdParm[0] = param;
100 return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
103 static BOOL metadc_param2( HDC hdc, short func, short param1, short param2 )
105 char buffer[FIELD_OFFSET(METARECORD, rdParm[2])];
106 METARECORD *mr = (METARECORD *)&buffer;
108 mr->rdSize = sizeof(buffer) / sizeof(WORD);
109 mr->rdFunction = func;
110 mr->rdParm[0] = param2;
111 mr->rdParm[1] = param1;
112 return metadc_record( hdc, mr, sizeof(buffer) );
115 static BOOL metadc_param4( HDC hdc, short func, short param1, short param2,
116 short param3, short param4 )
118 char buffer[FIELD_OFFSET(METARECORD, rdParm[4])];
119 METARECORD *mr = (METARECORD *)&buffer;
121 mr->rdSize = sizeof(buffer) / sizeof(WORD);
122 mr->rdFunction = func;
123 mr->rdParm[0] = param4;
124 mr->rdParm[1] = param3;
125 mr->rdParm[2] = param2;
126 mr->rdParm[3] = param1;
127 return metadc_record( hdc, mr, sizeof(buffer) );
130 static BOOL metadc_param5( HDC hdc, short func, short param1, short param2,
131 short param3, short param4, short param5 )
133 char buffer[FIELD_OFFSET(METARECORD, rdParm[5])];
134 METARECORD *mr = (METARECORD *)&buffer;
136 mr->rdSize = sizeof(buffer) / sizeof(WORD);
137 mr->rdFunction = func;
138 mr->rdParm[0] = param5;
139 mr->rdParm[1] = param4;
140 mr->rdParm[2] = param3;
141 mr->rdParm[3] = param2;
142 mr->rdParm[4] = param1;
143 return metadc_record( hdc, mr, sizeof(buffer) );
146 static BOOL metadc_param6( HDC hdc, short func, short param1, short param2,
147 short param3, short param4, short param5,
148 short param6 )
150 char buffer[FIELD_OFFSET(METARECORD, rdParm[6])];
151 METARECORD *mr = (METARECORD *)&buffer;
153 mr->rdSize = sizeof(buffer) / sizeof(WORD);
154 mr->rdFunction = func;
155 mr->rdParm[0] = param6;
156 mr->rdParm[1] = param5;
157 mr->rdParm[2] = param4;
158 mr->rdParm[3] = param3;
159 mr->rdParm[4] = param2;
160 mr->rdParm[5] = param1;
161 return metadc_record( hdc, mr, sizeof(buffer) );
164 static BOOL metadc_param8( HDC hdc, short func, short param1, short param2,
165 short param3, short param4, short param5,
166 short param6, short param7, short param8)
168 char buffer[FIELD_OFFSET(METARECORD, rdParm[8])];
169 METARECORD *mr = (METARECORD *)&buffer;
171 mr->rdSize = sizeof(buffer) / sizeof(WORD);
172 mr->rdFunction = func;
173 mr->rdParm[0] = param8;
174 mr->rdParm[1] = param7;
175 mr->rdParm[2] = param6;
176 mr->rdParm[3] = param5;
177 mr->rdParm[4] = param4;
178 mr->rdParm[5] = param3;
179 mr->rdParm[6] = param2;
180 mr->rdParm[7] = param1;
181 return metadc_record( hdc, mr, sizeof(buffer) );
184 BOOL METADC_SaveDC( HDC hdc )
186 return metadc_param0( hdc, META_SAVEDC );
189 BOOL METADC_RestoreDC( HDC hdc, INT level )
191 return metadc_param1( hdc, META_RESTOREDC, level );
194 BOOL METADC_SetTextAlign( HDC hdc, UINT align )
196 return metadc_param2( hdc, META_SETTEXTALIGN, HIWORD(align), LOWORD(align) );
199 BOOL METADC_SetBkMode( HDC hdc, INT mode )
201 return metadc_param1( hdc, META_SETBKMODE, (WORD)mode );
204 BOOL METADC_SetBkColor( HDC hdc, COLORREF color )
206 return metadc_param2( hdc, META_SETBKCOLOR, HIWORD(color), LOWORD(color) );
209 BOOL METADC_SetTextColor( HDC hdc, COLORREF color )
211 return metadc_param2( hdc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color) );
214 BOOL METADC_SetROP2( HDC hdc, INT rop )
216 return metadc_param1( hdc, META_SETROP2, (WORD)rop );
219 BOOL METADC_SetRelAbs( HDC hdc, INT mode )
221 return metadc_param1( hdc, META_SETRELABS, (WORD)mode );
224 BOOL METADC_SetPolyFillMode( HDC hdc, INT mode )
226 return metadc_param1( hdc, META_SETPOLYFILLMODE, mode );
229 BOOL METADC_SetStretchBltMode( HDC hdc, INT mode )
231 return metadc_param1( hdc, META_SETSTRETCHBLTMODE, mode );
234 BOOL METADC_IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
236 return metadc_param4( hdc, META_INTERSECTCLIPRECT, left, top, right, bottom );
239 BOOL METADC_ExcludeClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
241 return metadc_param4( hdc, META_EXCLUDECLIPRECT, left, top, right, bottom );
244 BOOL METADC_OffsetClipRgn( HDC hdc, INT x, INT y )
246 return metadc_param2( hdc, META_OFFSETCLIPRGN, x, y );
249 BOOL METADC_SetLayout( HDC hdc, DWORD layout )
251 return metadc_param2( hdc, META_SETLAYOUT, HIWORD(layout), LOWORD(layout) );
254 BOOL METADC_SetMapMode( HDC hdc, INT mode )
256 return metadc_param1( hdc, META_SETMAPMODE, mode );
259 BOOL METADC_SetViewportExtEx( HDC hdc, INT x, INT y )
261 return metadc_param2( hdc, META_SETVIEWPORTEXT, x, y );
264 BOOL METADC_SetViewportOrgEx( HDC hdc, INT x, INT y )
266 return metadc_param2( hdc, META_SETVIEWPORTORG, x, y );
269 BOOL METADC_SetWindowExtEx( HDC hdc, INT x, INT y )
271 return metadc_param2( hdc, META_SETWINDOWEXT, x, y );
274 BOOL METADC_SetWindowOrgEx( HDC hdc, INT x, INT y )
276 return metadc_param2( hdc, META_SETWINDOWORG, x, y );
279 BOOL METADC_OffsetViewportOrgEx( HDC hdc, INT x, INT y )
281 return metadc_param2( hdc, META_OFFSETVIEWPORTORG, x, y );
284 BOOL METADC_OffsetWindowOrgEx( HDC hdc, INT x, INT y )
286 return metadc_param2( hdc, META_OFFSETWINDOWORG, x, y );
289 BOOL METADC_ScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
291 return metadc_param4( hdc, META_SCALEVIEWPORTEXT, x_num, x_denom, y_num, y_denom );
294 BOOL METADC_ScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
296 return metadc_param4( hdc, META_SCALEWINDOWEXT, x_num, x_denom, y_num, y_denom );
299 BOOL METADC_SetTextJustification( HDC hdc, INT extra, INT breaks )
301 return metadc_param2( hdc, META_SETTEXTJUSTIFICATION, extra, breaks );
304 BOOL METADC_SetTextCharacterExtra( HDC hdc, INT extra )
306 return metadc_param1( hdc, META_SETTEXTCHAREXTRA, extra );
309 BOOL METADC_SetMapperFlags( HDC hdc, DWORD flags )
311 return metadc_param2( hdc, META_SETMAPPERFLAGS, HIWORD(flags), LOWORD(flags) );
314 BOOL METADC_MoveTo( HDC hdc, INT x, INT y )
316 return metadc_param2( hdc, META_MOVETO, x, y );
319 BOOL METADC_LineTo( HDC hdc, INT x, INT y )
321 return metadc_param2( hdc, META_LINETO, x, y );
324 BOOL METADC_Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
325 INT xstart, INT ystart, INT xend, INT yend )
327 return metadc_param8( hdc, META_ARC, left, top, right, bottom,
328 xstart, ystart, xend, yend );
331 BOOL METADC_Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
332 INT xstart, INT ystart, INT xend, INT yend )
334 return metadc_param8( hdc, META_PIE, left, top, right, bottom,
335 xstart, ystart, xend, yend );
338 BOOL METADC_Chord( HDC hdc, INT left, INT top, INT right, INT bottom,
339 INT xstart, INT ystart, INT xend, INT yend )
341 return metadc_param8( hdc, META_CHORD, left, top, right, bottom,
342 xstart, ystart, xend, yend );
345 BOOL METADC_Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom )
347 return metadc_param4( hdc, META_ELLIPSE, left, top, right, bottom );
350 BOOL METADC_Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom )
352 return metadc_param4( hdc, META_RECTANGLE, left, top, right, bottom );
355 BOOL METADC_RoundRect( HDC hdc, INT left, INT top, INT right,
356 INT bottom, INT ell_width, INT ell_height )
358 return metadc_param6( hdc, META_ROUNDRECT, left, top, right, bottom,
359 ell_width, ell_height );
362 BOOL METADC_SetPixel( HDC hdc, INT x, INT y, COLORREF color )
364 return metadc_param4( hdc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color) );
367 static BOOL metadc_poly( HDC hdc, short func, POINTS *pt, short count )
369 BOOL ret;
370 DWORD len;
371 METARECORD *mr;
373 len = sizeof(METARECORD) + count * 4;
374 if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
375 return FALSE;
377 mr->rdSize = len / 2;
378 mr->rdFunction = func;
379 *(mr->rdParm) = count;
380 memcpy(mr->rdParm + 1, pt, count * 4);
381 ret = metadc_record( hdc, mr, mr->rdSize * 2);
382 HeapFree( GetProcessHeap(), 0, mr);
383 return ret;
386 BOOL METADC_Polyline( HDC hdc, const POINT *pt, INT count )
388 int i;
389 POINTS *pts;
390 BOOL ret;
392 pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
393 if(!pts) return FALSE;
394 for (i=count;i--;)
396 pts[i].x = pt[i].x;
397 pts[i].y = pt[i].y;
399 ret = metadc_poly( hdc, META_POLYLINE, pts, count );
401 HeapFree( GetProcessHeap(), 0, pts );
402 return ret;
405 BOOL METADC_Polygon( HDC hdc, const POINT *pt, INT count )
407 int i;
408 POINTS *pts;
409 BOOL ret;
411 pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
412 if(!pts) return FALSE;
413 for (i = count; i--;)
415 pts[i].x = pt[i].x;
416 pts[i].y = pt[i].y;
418 ret = metadc_poly( hdc, META_POLYGON, pts, count );
420 HeapFree( GetProcessHeap(), 0, pts );
421 return ret;
424 BOOL METADC_PolyPolygon( HDC hdc, const POINT *pt, const INT *counts, UINT polygons )
426 BOOL ret;
427 DWORD len;
428 METARECORD *mr;
429 unsigned int i,j;
430 POINTS *pts;
431 INT16 totalpoint16 = 0;
432 INT16 * pointcounts;
434 for (i = 0; i < polygons; i++)
435 totalpoint16 += counts[i];
437 /* allocate space for all points */
438 pts=HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * totalpoint16 );
439 pointcounts = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * totalpoint16 );
441 /* copy point counts */
442 for (i = 0; i < polygons; i++)
443 pointcounts[i] = counts[i];
445 /* convert all points */
446 for (j = totalpoint16; j--;)
448 pts[j].x = pt[j].x;
449 pts[j].y = pt[j].y;
452 len = sizeof(METARECORD) + sizeof(WORD) + polygons * sizeof(INT16) +
453 totalpoint16 * sizeof(*pts);
455 if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
457 HeapFree( GetProcessHeap(), 0, pts );
458 HeapFree( GetProcessHeap(), 0, pointcounts );
459 return FALSE;
462 mr->rdSize = len / sizeof(WORD);
463 mr->rdFunction = META_POLYPOLYGON;
464 *mr->rdParm = polygons;
465 memcpy( mr->rdParm + 1, pointcounts, polygons * sizeof(INT16) );
466 memcpy( mr->rdParm + 1+polygons, pts , totalpoint16 * sizeof(*pts) );
467 ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
469 HeapFree( GetProcessHeap(), 0, pts );
470 HeapFree( GetProcessHeap(), 0, pointcounts );
471 HeapFree( GetProcessHeap(), 0, mr);
472 return ret;
475 BOOL METADC_ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, UINT fill_type )
477 return metadc_param5( hdc, META_EXTFLOODFILL, x, y, HIWORD(color), LOWORD(color), fill_type );
480 static UINT metadc_add_handle( struct metadc *metadc, HGDIOBJ obj )
482 UINT16 index;
484 for (index = 0; index < metadc->handles_size; index++)
485 if (metadc->handles[index] == 0) break;
486 if(index == metadc->handles_size)
488 metadc->handles_size += HANDLE_LIST_INC;
489 metadc->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
490 metadc->handles,
491 metadc->handles_size * sizeof(metadc->handles[0]) );
493 metadc->handles[index] = obj;
495 metadc->cur_handles++;
496 if (metadc->cur_handles > metadc->mh->mtNoObjects)
497 metadc->mh->mtNoObjects++;
499 return index ; /* index 0 is not reserved for metafiles */
502 static BOOL metadc_remove_handle( struct metadc *metadc, UINT index )
504 BOOL ret = FALSE;
506 if (index < metadc->handles_size && metadc->handles[index])
508 metadc->handles[index] = 0;
509 metadc->cur_handles--;
510 ret = TRUE;
512 return ret;
515 static INT16 metadc_create_brush( struct metadc *metadc, HBRUSH brush )
517 DWORD size;
518 METARECORD *mr;
519 LOGBRUSH logbrush;
520 BOOL r;
522 if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return -1;
524 switch (logbrush.lbStyle)
526 case BS_SOLID:
527 case BS_NULL:
528 case BS_HATCHED:
530 LOGBRUSH16 lb16;
532 lb16.lbStyle = logbrush.lbStyle;
533 lb16.lbColor = logbrush.lbColor;
534 lb16.lbHatch = logbrush.lbHatch;
535 size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - sizeof(WORD);
536 mr = HeapAlloc( GetProcessHeap(), 0, size );
537 mr->rdSize = size / sizeof(WORD);
538 mr->rdFunction = META_CREATEBRUSHINDIRECT;
539 memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16) );
540 break;
542 case BS_PATTERN:
543 case BS_DIBPATTERN:
545 char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
546 BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
547 DWORD info_size;
548 UINT usage;
550 if (!NtGdiIcmBrushInfo( 0, brush, src_info, NULL, NULL, &usage, NULL, 0 ))
551 goto done;
553 info_size = get_dib_info_size( src_info, usage );
554 size = FIELD_OFFSET( METARECORD, rdParm[2] ) +
555 info_size + src_info->bmiHeader.biSizeImage;
557 if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
558 mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
559 mr->rdSize = size / sizeof(WORD);
560 mr->rdParm[0] = logbrush.lbStyle;
561 mr->rdParm[1] = usage;
562 dst_info = (BITMAPINFO *)(mr->rdParm + 2);
563 NtGdiIcmBrushInfo( 0, brush, dst_info, (char *)dst_info + info_size, NULL, NULL, NULL, 0 );
564 if (dst_info->bmiHeader.biClrUsed == 1 << dst_info->bmiHeader.biBitCount)
565 dst_info->bmiHeader.biClrUsed = 0;
566 break;
569 default:
570 FIXME( "Unknown brush style %x\n", logbrush.lbStyle );
571 return 0;
574 r = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
575 HeapFree(GetProcessHeap(), 0, mr);
576 if (!r) return -1;
577 done:
578 return metadc_add_handle( metadc, brush );
581 static INT16 metadc_create_region( struct metadc *metadc, HRGN hrgn )
583 DWORD len;
584 METARECORD *mr;
585 RGNDATA *rgndata;
586 RECT *cur_rect, *end_rect;
587 WORD bands = 0, max_bounds = 0;
588 WORD *param, *start_band;
589 BOOL ret;
591 if (!(len = NtGdiGetRegionData( hrgn, 0, NULL ))) return -1;
592 if (!(rgndata = HeapAlloc( GetProcessHeap(), 0, len )))
594 WARN( "Can't alloc rgndata buffer\n" );
595 return -1;
597 NtGdiGetRegionData( hrgn, len, rgndata );
599 /* Overestimate of length:
600 * Assume every rect is a separate band -> 6 WORDs per rect,
601 * see MF_Play_MetaCreateRegion for format details.
603 len = sizeof(METARECORD) + 20 + rgndata->rdh.nCount * 12;
604 if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
606 WARN( "Can't alloc METARECORD buffer\n" );
607 HeapFree( GetProcessHeap(), 0, rgndata );
608 return -1;
611 param = mr->rdParm + 11;
612 start_band = NULL;
614 end_rect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
615 for (cur_rect = (RECT *)rgndata->Buffer; cur_rect < end_rect; cur_rect++)
617 if (start_band && cur_rect->top == start_band[1])
619 *param++ = cur_rect->left;
620 *param++ = cur_rect->right;
622 else
624 if (start_band)
626 *start_band = param - start_band - 3;
627 *param++ = *start_band;
628 if (*start_band > max_bounds)
629 max_bounds = *start_band;
630 bands++;
632 start_band = param++;
633 *param++ = cur_rect->top;
634 *param++ = cur_rect->bottom;
635 *param++ = cur_rect->left;
636 *param++ = cur_rect->right;
640 if (start_band)
642 *start_band = param - start_band - 3;
643 *param++ = *start_band;
644 if (*start_band > max_bounds)
645 max_bounds = *start_band;
646 bands++;
649 mr->rdParm[0] = 0;
650 mr->rdParm[1] = 6;
651 mr->rdParm[2] = 0x2f6;
652 mr->rdParm[3] = 0;
653 mr->rdParm[4] = (param - &mr->rdFunction) * sizeof(WORD);
654 mr->rdParm[5] = bands;
655 mr->rdParm[6] = max_bounds;
656 mr->rdParm[7] = rgndata->rdh.rcBound.left;
657 mr->rdParm[8] = rgndata->rdh.rcBound.top;
658 mr->rdParm[9] = rgndata->rdh.rcBound.right;
659 mr->rdParm[10] = rgndata->rdh.rcBound.bottom;
660 mr->rdFunction = META_CREATEREGION;
661 mr->rdSize = param - (WORD *)mr;
662 ret = metadc_write_record( metadc, mr, mr->rdSize * 2 );
663 HeapFree( GetProcessHeap(), 0, mr );
664 HeapFree( GetProcessHeap(), 0, rgndata );
665 if (!ret)
667 WARN("MFDRV_WriteRecord failed\n");
668 return -1;
670 return metadc_add_handle( metadc, hrgn );
673 BOOL METADC_PaintRgn( HDC hdc, HRGN hrgn )
675 struct metadc *metadc;
676 INT16 index;
677 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
678 index = metadc_create_region( metadc, hrgn );
679 if(index == -1) return FALSE;
680 return metadc_param1( hdc, META_PAINTREGION, index );
683 BOOL METADC_InvertRgn( HDC hdc, HRGN hrgn )
685 struct metadc *metadc;
686 INT16 index;
687 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
688 index = metadc_create_region( metadc, hrgn );
689 if (index == -1) return FALSE;
690 return metadc_param1( hdc, META_INVERTREGION, index );
693 BOOL METADC_FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
695 struct metadc *metadc;
696 INT16 rgn, brush;
698 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
700 rgn = metadc_create_region( metadc, hrgn );
701 if (rgn == -1) return FALSE;
702 brush = metadc_create_brush( metadc, hbrush );
703 if (!brush) return FALSE;
704 return metadc_param2( hdc, META_FILLREGION, rgn, brush );
707 BOOL METADC_FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, INT x, INT y )
709 struct metadc *metadc;
710 INT16 rgn, brush;
712 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
713 rgn = metadc_create_region( metadc, hrgn );
714 if (rgn == -1) return FALSE;
715 brush = metadc_create_brush( metadc, hbrush );
716 if (!brush) return FALSE;
717 return metadc_param4( hdc, META_FRAMEREGION, rgn, brush, x, y );
720 BOOL METADC_PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop )
722 return metadc_param6( hdc, META_PATBLT, left, top, width, height,
723 HIWORD(rop), LOWORD(rop) );
726 static BOOL metadc_stretchblt( HDC hdc, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
727 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
728 DWORD rop, WORD type )
730 BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
731 UINT bmi_size, size, bpp;
732 int i = 0, bitmap_offset;
733 BITMAPINFO *bmi;
734 METARECORD *mr;
735 HBITMAP bitmap;
736 BOOL ret;
738 if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
739 if (!GetDIBits( hdc_src, bitmap, 0, INT_MAX, NULL, &src_info, DIB_RGB_COLORS )) return FALSE;
741 bpp = src_info.bmiHeader.biBitCount;
742 if (bpp <= 8)
743 bmi_size = sizeof(BITMAPINFOHEADER) + (1 << bpp) * sizeof(RGBQUAD);
744 else if (bpp == 16 || bpp == 32)
745 bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
746 else
747 bmi_size = sizeof(BITMAPINFOHEADER);
749 bitmap_offset = type == META_DIBBITBLT ? 8 : 10;
750 size = FIELD_OFFSET( METARECORD, rdParm[bitmap_offset] ) + bmi_size +
751 src_info.bmiHeader.biSizeImage;
752 if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
753 mr->rdFunction = type;
754 bmi = (BITMAPINFO *)&mr->rdParm[bitmap_offset];
755 bmi->bmiHeader = src_info.bmiHeader;
756 TRACE( "size = %u rop=%lx\n", size, rop );
758 ret = GetDIBits( hdc_src, bitmap, 0, src_info.bmiHeader.biHeight, (BYTE *)bmi + bmi_size,
759 bmi, DIB_RGB_COLORS );
760 if (ret)
762 mr->rdSize = size / sizeof(WORD);
763 mr->rdParm[i++] = LOWORD(rop);
764 mr->rdParm[i++] = HIWORD(rop);
765 if (bitmap_offset > 8)
767 mr->rdParm[i++] = height_src;
768 mr->rdParm[i++] = width_src;
770 mr->rdParm[i++] = y_src;
771 mr->rdParm[i++] = x_src;
772 mr->rdParm[i++] = height_dst;
773 mr->rdParm[i++] = width_dst;
774 mr->rdParm[i++] = y_dst;
775 mr->rdParm[i++] = x_dst;
776 ret = metadc_record( hdc, mr, size );
779 HeapFree( GetProcessHeap(), 0, mr);
780 return ret;
783 BOOL METADC_BitBlt( HDC hdc, INT x_dst, INT y_dst, INT width, INT height,
784 HDC hdc_src, INT x_src, INT y_src, DWORD rop )
786 return metadc_stretchblt( hdc, x_dst, y_dst, width, height,
787 hdc_src, x_src, y_src, width, height, rop, META_DIBBITBLT );
790 BOOL METADC_StretchBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
791 HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
792 DWORD rop )
794 return metadc_stretchblt( hdc_dst, x_dst, y_dst, width_dst, height_dst,
795 hdc_src, x_src, y_src, width_src, height_src, rop, META_DIBSTRETCHBLT );
798 INT METADC_StretchDIBits( HDC hdc, INT x_dst, INT y_dst, INT width_dst,
799 INT height_dst, INT x_src, INT y_src, INT width_src,
800 INT height_src, const void *bits,
801 const BITMAPINFO *info, UINT usage, DWORD rop )
803 DWORD infosize = get_dib_info_size( info, usage );
804 DWORD len = sizeof(METARECORD) + 10 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
805 METARECORD *mr;
807 if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
809 mr->rdSize = len / sizeof(WORD);
810 mr->rdFunction = META_STRETCHDIB;
811 mr->rdParm[0] = LOWORD(rop);
812 mr->rdParm[1] = HIWORD(rop);
813 mr->rdParm[2] = usage;
814 mr->rdParm[3] = height_src;
815 mr->rdParm[4] = width_src;
816 mr->rdParm[5] = y_src;
817 mr->rdParm[6] = x_src;
818 mr->rdParm[7] = height_dst;
819 mr->rdParm[8] = width_dst;
820 mr->rdParm[9] = y_dst;
821 mr->rdParm[10] = x_dst;
822 memcpy( mr->rdParm + 11, info, infosize );
823 memcpy( mr->rdParm + 11 + infosize / 2, bits, info->bmiHeader.biSizeImage );
824 metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
825 HeapFree( GetProcessHeap(), 0, mr );
826 return height_src;
829 INT METADC_SetDIBitsToDevice( HDC hdc, INT x_dst, INT y_dst, DWORD width, DWORD height,
830 INT x_src, INT y_src, UINT startscan, UINT lines,
831 const void *bits, const BITMAPINFO *info, UINT coloruse )
834 DWORD infosize = get_dib_info_size(info, coloruse);
835 DWORD len = sizeof(METARECORD) + 8 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
836 METARECORD *mr;
838 if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
840 mr->rdSize = len / sizeof(WORD);
841 mr->rdFunction = META_SETDIBTODEV;
842 mr->rdParm[0] = coloruse;
843 mr->rdParm[1] = lines;
844 mr->rdParm[2] = startscan;
845 mr->rdParm[3] = y_src;
846 mr->rdParm[4] = x_src;
847 mr->rdParm[5] = height;
848 mr->rdParm[6] = width;
849 mr->rdParm[7] = y_dst;
850 mr->rdParm[8] = x_dst;
851 memcpy( mr->rdParm + 9, info, infosize );
852 memcpy( mr->rdParm + 9 + infosize / sizeof(WORD), bits, info->bmiHeader.biSizeImage );
853 metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
854 HeapFree( GetProcessHeap(), 0, mr );
855 return lines;
858 static BOOL metadc_text( HDC hdc, short x, short y, UINT16 flags, const RECT16 *rect,
859 const char *str, short count, const INT16 *dx )
861 BOOL ret;
862 DWORD len;
863 METARECORD *mr;
864 BOOL isrect = flags & (ETO_CLIPPED | ETO_OPAQUE);
866 len = sizeof(METARECORD) + (((count + 1) >> 1) * 2) + 2 * sizeof(short)
867 + sizeof(UINT16);
868 if (isrect) len += sizeof(RECT16);
869 if (dx) len += count * sizeof(INT16);
870 if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
872 mr->rdSize = len / sizeof(WORD);
873 mr->rdFunction = META_EXTTEXTOUT;
874 mr->rdParm[0] = y;
875 mr->rdParm[1] = x;
876 mr->rdParm[2] = count;
877 mr->rdParm[3] = flags;
878 if (isrect) memcpy( mr->rdParm + 4, rect, sizeof(RECT16) );
879 memcpy( mr->rdParm + (isrect ? 8 : 4), str, count );
880 if (dx)
881 memcpy( mr->rdParm + (isrect ? 8 : 4) + ((count + 1) >> 1), dx, count * sizeof(INT16) );
882 ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
883 HeapFree( GetProcessHeap(), 0, mr );
884 return ret;
887 BOOL METADC_ExtTextOut( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
888 const WCHAR *str, UINT count, const INT *dx )
890 RECT16 rect16;
891 LPINT16 lpdx16 = NULL;
892 BOOL ret;
893 unsigned int i, j;
894 char *ascii;
895 DWORD len;
896 CHARSETINFO csi;
897 int charset = GetTextCharset( hdc );
898 UINT cp = CP_ACP;
900 if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ))
901 cp = csi.ciACP;
902 else
904 switch(charset)
906 case OEM_CHARSET:
907 cp = GetOEMCP();
908 break;
909 case DEFAULT_CHARSET:
910 cp = GetACP();
911 break;
913 case VISCII_CHARSET:
914 case TCVN_CHARSET:
915 case KOI8_CHARSET:
916 case ISO3_CHARSET:
917 case ISO4_CHARSET:
918 case ISO10_CHARSET:
919 case CELTIC_CHARSET:
920 /* FIXME: These have no place here, but because x11drv
921 enumerates fonts with these (made up) charsets some apps
922 might use them and then the FIXME below would become
923 annoying. Now we could pick the intended codepage for
924 each of these, but since it's broken anyway we'll just
925 use CP_ACP and hope it'll go away...
927 cp = CP_ACP;
928 break;
930 default:
931 FIXME("Can't find codepage for charset %d\n", charset);
932 break;
937 TRACE( "cp = %d\n", cp );
938 len = WideCharToMultiByte( cp, 0, str, count, NULL, 0, NULL, NULL );
939 ascii = HeapAlloc( GetProcessHeap(), 0, len );
940 WideCharToMultiByte( cp, 0, str, count, ascii, len, NULL, NULL );
941 TRACE( "mapped %s -> %s\n", debugstr_wn(str, count), debugstr_an(ascii, len) );
944 if (lprect)
946 rect16.left = lprect->left;
947 rect16.top = lprect->top;
948 rect16.right = lprect->right;
949 rect16.bottom = lprect->bottom;
952 if (dx)
954 lpdx16 = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * len );
955 for (i = j = 0; i < len; )
956 if (IsDBCSLeadByteEx( cp, ascii[i] ))
958 lpdx16[i++] = dx[j++];
959 lpdx16[i++] = 0;
961 else
962 lpdx16[i++] = dx[j++];
965 ret = metadc_text( hdc, x, y, flags, lprect ? &rect16 : NULL, ascii, len, lpdx16 );
966 HeapFree( GetProcessHeap(), 0, ascii );
967 HeapFree( GetProcessHeap(), 0, lpdx16 );
968 return ret;
971 BOOL METADC_ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT mode )
973 struct metadc *metadc;
974 INT16 rgn;
975 INT ret;
977 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
978 if (mode != RGN_COPY) return ERROR;
979 if (!hrgn) return NULLREGION;
980 rgn = metadc_create_region( metadc, hrgn );
981 if(rgn == -1) return ERROR;
982 ret = metadc_param1( hdc, META_SELECTOBJECT, rgn ) ? NULLREGION : ERROR;
983 metadc_param1( hdc, META_DELETEOBJECT, rgn );
984 metadc_remove_handle( metadc, rgn );
985 return ret;
988 static INT16 metadc_find_object( struct metadc *metadc, HGDIOBJ obj )
990 INT16 index;
992 for (index = 0; index < metadc->handles_size; index++)
993 if (metadc->handles[index] == obj) return index;
995 return -1;
998 static void METADC_DeleteObject( HDC hdc, HGDIOBJ obj )
1000 struct metadc *metadc = get_metadc_ptr( hdc );
1001 METARECORD mr;
1002 INT16 index;
1004 if ((index = metadc_find_object( metadc, obj )) < 0) return;
1005 if (obj == metadc->pen || obj == metadc->brush || obj == metadc->font)
1007 WARN( "deleting selected object %p\n", obj );
1008 return;
1011 mr.rdSize = sizeof(mr) / sizeof(WORD);
1012 mr.rdFunction = META_DELETEOBJECT;
1013 mr.rdParm[0] = index;
1015 metadc_write_record( metadc, &mr, mr.rdSize * sizeof(WORD) );
1017 metadc->handles[index] = 0;
1018 metadc->cur_handles--;
1021 static BOOL metadc_select_object( HDC hdc, INT16 index)
1023 METARECORD mr;
1025 mr.rdSize = sizeof mr / 2;
1026 mr.rdFunction = META_SELECTOBJECT;
1027 mr.rdParm[0] = index;
1028 return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
1031 static HBRUSH METADC_SelectBrush( HDC hdc, HBRUSH hbrush )
1033 struct metadc *metadc = get_metadc_ptr( hdc );
1034 INT16 index;
1035 HBRUSH ret;
1037 index = metadc_find_object( metadc, hbrush );
1038 if( index < 0 )
1040 index = metadc_create_brush( metadc, hbrush );
1041 if( index < 0 )
1042 return 0;
1043 GDI_hdc_using_object( hbrush, hdc, METADC_DeleteObject );
1045 if (!metadc_select_object( hdc, index )) return 0;
1046 ret = metadc->brush;
1047 metadc->brush = hbrush;
1048 return ret;
1051 static UINT16 metadc_create_font( struct metadc *metadc, HFONT font, LOGFONTW *logfont )
1053 char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
1054 METARECORD *mr = (METARECORD *)&buffer;
1055 LOGFONT16 *font16;
1056 INT written;
1058 mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
1059 mr->rdFunction = META_CREATEFONTINDIRECT;
1060 font16 = (LOGFONT16 *)&mr->rdParm;
1062 font16->lfHeight = logfont->lfHeight;
1063 font16->lfWidth = logfont->lfWidth;
1064 font16->lfEscapement = logfont->lfEscapement;
1065 font16->lfOrientation = logfont->lfOrientation;
1066 font16->lfWeight = logfont->lfWeight;
1067 font16->lfItalic = logfont->lfItalic;
1068 font16->lfUnderline = logfont->lfUnderline;
1069 font16->lfStrikeOut = logfont->lfStrikeOut;
1070 font16->lfCharSet = logfont->lfCharSet;
1071 font16->lfOutPrecision = logfont->lfOutPrecision;
1072 font16->lfClipPrecision = logfont->lfClipPrecision;
1073 font16->lfQuality = logfont->lfQuality;
1074 font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
1075 written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName,
1076 LF_FACESIZE - 1, NULL, NULL );
1077 /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
1078 memset( font16->lfFaceName + written, 0, LF_FACESIZE - written );
1080 if (!metadc_write_record( metadc, mr, mr->rdSize * 2 ))
1081 return 0;
1082 return metadc_add_handle( metadc, font );
1085 static HFONT METADC_SelectFont( HDC hdc, HFONT hfont )
1087 struct metadc *metadc = get_metadc_ptr( hdc );
1088 LOGFONTW font;
1089 INT16 index;
1090 HFONT ret;
1092 index = metadc_find_object( metadc, hfont );
1093 if (index < 0)
1095 if (!GetObjectW( hfont, sizeof(font), &font ))
1096 return 0;
1097 index = metadc_create_font( metadc, hfont, &font );
1098 if( index < 0 )
1099 return 0;
1100 GDI_hdc_using_object( hfont, hdc, METADC_DeleteObject );
1102 if (!metadc_select_object( hdc, index )) return 0;
1103 ret = metadc->font;
1104 metadc->font = hfont;
1105 return ret;
1108 static UINT16 metadc_create_pen( struct metadc *metadc, HPEN pen, LOGPEN16 *logpen )
1110 char buffer[FIELD_OFFSET(METARECORD, rdParm[sizeof(*logpen) / sizeof(WORD)])];
1111 METARECORD *mr = (METARECORD *)&buffer;
1113 mr->rdSize = sizeof(buffer) / sizeof(WORD);
1114 mr->rdFunction = META_CREATEPENINDIRECT;
1115 memcpy( mr->rdParm, logpen, sizeof(*logpen) );
1116 if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) )) return 0;
1117 return metadc_add_handle( metadc, pen );
1120 static HPEN METADC_SelectPen( HDC hdc, HPEN hpen )
1122 struct metadc *metadc = get_metadc_ptr( hdc );
1123 LOGPEN16 logpen;
1124 INT16 index;
1125 HPEN ret;
1127 index = metadc_find_object( metadc, hpen );
1128 if (index < 0)
1130 /* must be an extended pen */
1131 INT size = GetObjectW( hpen, 0, NULL );
1133 if (!size) return 0;
1135 if (size == sizeof(LOGPEN))
1137 LOGPEN pen;
1139 GetObjectW( hpen, sizeof(pen), &pen );
1140 logpen.lopnStyle = pen.lopnStyle;
1141 logpen.lopnWidth.x = pen.lopnWidth.x;
1142 logpen.lopnWidth.y = pen.lopnWidth.y;
1143 logpen.lopnColor = pen.lopnColor;
1145 else /* must be an extended pen */
1147 EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
1149 GetObjectW( hpen, size, elp );
1150 /* FIXME: add support for user style pens */
1151 logpen.lopnStyle = elp->elpPenStyle;
1152 logpen.lopnWidth.x = elp->elpWidth;
1153 logpen.lopnWidth.y = 0;
1154 logpen.lopnColor = elp->elpColor;
1156 HeapFree( GetProcessHeap(), 0, elp );
1159 index = metadc_create_pen( metadc, hpen, &logpen );
1160 if( index < 0 )
1161 return 0;
1162 GDI_hdc_using_object( hpen, hdc, METADC_DeleteObject );
1165 if (!metadc_select_object( hdc, index )) return 0;
1166 ret = metadc->pen;
1167 metadc->pen = hpen;
1168 return ret;
1171 static BOOL metadc_create_palette( struct metadc *metadc, HPALETTE palette,
1172 LOGPALETTE *log_palette, int sizeofPalette )
1174 int index;
1175 BOOL ret;
1176 METARECORD *mr;
1178 mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
1179 if (!mr) return FALSE;
1180 mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
1181 mr->rdFunction = META_CREATEPALETTE;
1182 memcpy(&(mr->rdParm), log_palette, sizeofPalette);
1183 if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) ))
1185 HeapFree(GetProcessHeap(), 0, mr);
1186 return FALSE;
1189 mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
1190 mr->rdFunction = META_SELECTPALETTE;
1192 if ((index = metadc_add_handle( metadc, palette )) == -1) ret = FALSE;
1193 else
1195 mr->rdParm[0] = index;
1196 ret = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
1198 HeapFree( GetProcessHeap(), 0, mr );
1199 return ret;
1202 BOOL METADC_SelectPalette( HDC hdc, HPALETTE palette )
1204 struct metadc *metadc;
1205 PLOGPALETTE log_palette;
1206 WORD count = 0;
1207 BOOL ret;
1208 int size;
1210 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1211 GetObjectA( palette, sizeof(WORD), &count );
1212 if (!count) return 0;
1214 size = sizeof(LOGPALETTE) + (count - 1) * sizeof(PALETTEENTRY);
1215 log_palette = HeapAlloc( GetProcessHeap(), 0, size );
1216 if (!log_palette) return 0;
1218 log_palette->palVersion = 0x300;
1219 log_palette->palNumEntries = count;
1221 GetPaletteEntries( palette, 0, count, log_palette->palPalEntry );
1223 ret = metadc_create_palette( metadc, palette, log_palette, size );
1225 HeapFree( GetProcessHeap(), 0, log_palette );
1226 return ret;
1229 BOOL METADC_RealizePalette( HDC hdc )
1231 return metadc_param0( hdc, META_REALIZEPALETTE );
1234 HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj )
1236 switch (gdi_handle_type( obj ))
1238 case NTGDI_OBJ_BRUSH:
1239 return METADC_SelectBrush( hdc, obj );
1240 case NTGDI_OBJ_FONT:
1241 return METADC_SelectFont( hdc, obj );
1242 case NTGDI_OBJ_PEN:
1243 case NTGDI_OBJ_EXTPEN:
1244 return METADC_SelectPen( hdc, obj );
1245 default:
1246 SetLastError( ERROR_INVALID_FUNCTION );
1247 return 0;
1251 BOOL METADC_ExtEscape( HDC hdc, INT escape, INT input_size, const void *input,
1252 INT output_size, void *output )
1254 METARECORD *mr;
1255 DWORD len;
1256 BOOL ret;
1258 if (output_size) return FALSE; /* escapes that require output cannot work in metafiles */
1260 len = sizeof(*mr) + sizeof(WORD) + ((input_size + 1) & ~1);
1261 if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
1262 mr->rdSize = len / sizeof(WORD);
1263 mr->rdFunction = META_ESCAPE;
1264 mr->rdParm[0] = escape;
1265 mr->rdParm[1] = input_size;
1266 memcpy( &mr->rdParm[2], input, input_size );
1267 ret = metadc_record( hdc, mr, len );
1268 HeapFree(GetProcessHeap(), 0, mr);
1269 return ret;
1272 INT METADC_GetDeviceCaps( HDC hdc, INT cap )
1274 if (!get_metadc_ptr( hdc )) return 0;
1276 switch(cap)
1278 case TECHNOLOGY:
1279 return DT_METAFILE;
1280 case TEXTCAPS:
1281 return 0;
1282 default:
1283 TRACE(" unsupported capability %d, will return 0\n", cap );
1285 return 0;
1288 static void metadc_free( struct metadc *metadc )
1290 DWORD index;
1292 CloseHandle( metadc->hFile );
1293 HeapFree( GetProcessHeap(), 0, metadc->mh );
1294 for(index = 0; index < metadc->handles_size; index++)
1295 if(metadc->handles[index])
1296 GDI_hdc_not_using_object( metadc->handles[index], metadc->hdc );
1297 HeapFree( GetProcessHeap(), 0, metadc->handles );
1298 HeapFree( GetProcessHeap(), 0, metadc );
1301 BOOL METADC_DeleteDC( HDC hdc )
1303 struct metadc *metadc;
1305 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1306 if (!NtGdiDeleteClientObj( hdc )) return FALSE;
1307 metadc_free( metadc );
1308 return TRUE;
1311 /**********************************************************************
1312 * CreateMetaFileW (GDI32.@)
1314 * Create a new DC and associate it with a metafile. Pass a filename
1315 * to create a disk-based metafile, NULL to create a memory metafile.
1317 HDC WINAPI CreateMetaFileW( const WCHAR *filename )
1319 struct metadc *metadc;
1320 HANDLE hdc;
1322 TRACE( "%s\n", debugstr_w(filename) );
1324 if (!(hdc = NtGdiCreateClientObj( NTGDI_OBJ_METADC ))) return NULL;
1326 metadc = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc) );
1327 if (!metadc)
1329 NtGdiDeleteClientObj( hdc );
1330 return NULL;
1332 if (!(metadc->mh = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc->mh) )))
1334 HeapFree( GetProcessHeap(), 0, metadc );
1335 NtGdiDeleteClientObj( hdc );
1336 return NULL;
1339 metadc->hdc = hdc;
1340 set_gdi_client_ptr( hdc, metadc );
1342 metadc->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1343 HANDLE_LIST_INC * sizeof(metadc->handles[0]) );
1344 metadc->handles_size = HANDLE_LIST_INC;
1345 metadc->cur_handles = 0;
1347 metadc->hFile = 0;
1349 metadc->mh->mtHeaderSize = sizeof(METAHEADER) / sizeof(WORD);
1350 metadc->mh->mtVersion = 0x0300;
1351 metadc->mh->mtSize = metadc->mh->mtHeaderSize;
1352 metadc->mh->mtNoObjects = 0;
1353 metadc->mh->mtMaxRecord = 0;
1354 metadc->mh->mtNoParameters = 0;
1355 metadc->mh->mtType = METAFILE_MEMORY;
1357 metadc->pen = GetStockObject( BLACK_PEN );
1358 metadc->brush = GetStockObject( WHITE_BRUSH );
1359 metadc->font = GetStockObject( DEVICE_DEFAULT_FONT );
1361 if (filename) /* disk based metafile */
1363 HANDLE file = CreateFileW( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
1364 if (file == INVALID_HANDLE_VALUE)
1366 HeapFree( GetProcessHeap(), 0, metadc );
1367 NtGdiDeleteClientObj( hdc );
1368 return 0;
1370 metadc->hFile = file;
1373 TRACE( "returning %p\n", hdc );
1374 return hdc;
1377 /**********************************************************************
1378 * CreateMetaFileA (GDI32.@)
1380 HDC WINAPI CreateMetaFileA( const char *filename )
1382 LPWSTR filenameW;
1383 DWORD len;
1384 HDC hdc;
1386 if (!filename) return CreateMetaFileW( NULL );
1388 len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
1389 filenameW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1390 MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
1392 hdc = CreateMetaFileW( filenameW );
1394 HeapFree( GetProcessHeap(), 0, filenameW );
1395 return hdc;
1398 /******************************************************************
1399 * CloseMetaFile (GDI32.@)
1401 * Stop recording graphics operations in metafile associated with
1402 * hdc and retrieve metafile.
1404 HMETAFILE WINAPI CloseMetaFile( HDC hdc )
1406 struct metadc *metadc;
1407 DWORD bytes_written;
1408 HMETAFILE hmf;
1410 TRACE( "(%p)\n", hdc );
1412 if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1414 /* Construct the end of metafile record - this is documented
1415 * in SDK Knowledgebase Q99334.
1417 if (!metadc_param0( hdc, META_EOF )) return FALSE;
1418 if (!NtGdiDeleteClientObj( hdc )) return FALSE;
1420 if (metadc->hFile && !WriteFile( metadc->hFile, metadc->mh, metadc->mh->mtSize * sizeof(WORD),
1421 &bytes_written, NULL ))
1423 metadc_free( metadc );
1424 return FALSE;
1427 /* Now allocate a global handle for the metafile */
1428 hmf = MF_Create_HMETAFILE( metadc->mh );
1429 if (hmf) metadc->mh = NULL; /* So it won't be deleted */
1430 metadc_free( metadc );
1431 return hmf;