xref: /reactos/win32ss/gdi/gdi32/wine/metadc.c (revision 8767aada)
1 /*
2  * Metafile DC functions
3  *
4  * Copyright 1999 Huw D M Davies
5  * Copyright 1993, 1994, 1996 Alexandre Julliard
6  * Copyright 2021 Jacek Caban for CodeWeavers
7  *
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.
12  *
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.
17  *
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
21  */
22 
23 #include "wine/config.h"
24 
25 #include <stdarg.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winnls.h"
33 #include "winerror.h"
34 #include "gdi_private.h"
35 #ifdef __REACTOS__
36 #include "wine/winternl.h"
37 #else
38 #include "winternl.h"
39 #endif
40 #include "wine/wingdi16.h"
41 #include "wine/debug.h"
42 
43 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
44 
45 struct metadc
46 {
47     HDC         hdc;
48     METAHEADER *mh;           /* Pointer to metafile header */
49     UINT        handles_size, cur_handles;
50     HGDIOBJ    *handles;
51     HANDLE      hFile;          /* Handle for disk based MetaFile */
52     HPEN        pen;
53     HBRUSH      brush;
54     HFONT       font;
55 };
56 
57 #define HANDLE_LIST_INC 20
58 
59 
get_metadc_ptr(HDC hdc)60 struct metadc *get_metadc_ptr( HDC hdc )
61 {
62     struct metadc *metafile = GdiGetClientObjLink(hdc);//get_gdi_client_ptr( hdc, NTGDI_OBJ_METADC );
63     if (!metafile) SetLastError( ERROR_INVALID_HANDLE );
64     return metafile;
65 }
66 
metadc_write_record(struct metadc * metadc,METARECORD * mr,unsigned int rlen)67 static BOOL metadc_write_record( struct metadc *metadc, METARECORD *mr, unsigned int rlen )
68 {
69     DWORD len, size;
70     METAHEADER *mh;
71 
72     len = metadc->mh->mtSize * sizeof(WORD) + rlen;
73     size = HeapSize( GetProcessHeap(), 0, metadc->mh );
74     if (len > size)
75     {
76         size += size / sizeof(WORD) + rlen;
77         mh = HeapReAlloc( GetProcessHeap(), 0, metadc->mh, size );
78         if (!mh) return FALSE;
79         metadc->mh = mh;
80     }
81     memcpy( (WORD *)metadc->mh + metadc->mh->mtSize, mr, rlen );
82 
83     metadc->mh->mtSize += rlen / sizeof(WORD);
84     metadc->mh->mtMaxRecord = max( metadc->mh->mtMaxRecord, rlen / sizeof(WORD) );
85     return TRUE;
86 }
87 
metadc_record(HDC hdc,METARECORD * mr,DWORD rlen)88 static BOOL metadc_record( HDC hdc, METARECORD *mr, DWORD rlen )
89 {
90     struct metadc *metadc;
91 
92     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
93     return metadc_write_record( metadc, mr, rlen );
94 }
95 
metadc_param0(HDC hdc,short func)96 static BOOL metadc_param0( HDC hdc, short func )
97 {
98     METARECORD mr;
99 
100     mr.rdSize = FIELD_OFFSET(METARECORD, rdParm[0]) / sizeof(WORD);
101     mr.rdFunction = func;
102     return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
103 }
104 
metadc_param1(HDC hdc,short func,short param)105 static BOOL metadc_param1( HDC hdc, short func, short param )
106 {
107     METARECORD mr;
108 
109     mr.rdSize = sizeof(mr) / sizeof(WORD);
110     mr.rdFunction = func;
111     mr.rdParm[0] = param;
112     return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
113 }
114 
metadc_param2(HDC hdc,short func,short param1,short param2)115 static BOOL metadc_param2( HDC hdc, short func, short param1, short param2 )
116 {
117     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
118                    + 2*RTL_FIELD_SIZE(METARECORD, rdParm)];
119     METARECORD *mr = (METARECORD *)&buffer;
120 
121     mr->rdSize = sizeof(buffer) / sizeof(WORD);
122     mr->rdFunction = func;
123     mr->rdParm[0] = param2;
124     mr->rdParm[1] = param1;
125     return metadc_record( hdc, mr, sizeof(buffer) );
126 }
127 
metadc_param4(HDC hdc,short func,short param1,short param2,short param3,short param4)128 static BOOL metadc_param4( HDC hdc, short func, short param1, short param2,
129                            short param3, short param4 )
130 {
131     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
132                    + 4*RTL_FIELD_SIZE(METARECORD, rdParm)];
133     METARECORD *mr = (METARECORD *)&buffer;
134 
135     mr->rdSize = sizeof(buffer) / sizeof(WORD);
136     mr->rdFunction = func;
137     mr->rdParm[0] = param4;
138     mr->rdParm[1] = param3;
139     mr->rdParm[2] = param2;
140     mr->rdParm[3] = param1;
141     return metadc_record( hdc, mr, sizeof(buffer) );
142 }
143 
metadc_param5(HDC hdc,short func,short param1,short param2,short param3,short param4,short param5)144 static BOOL metadc_param5( HDC hdc, short func, short param1, short param2,
145                            short param3, short param4, short param5 )
146 {
147     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
148                    + 5*RTL_FIELD_SIZE(METARECORD, rdParm)];
149     METARECORD *mr = (METARECORD *)&buffer;
150 
151     mr->rdSize = sizeof(buffer) / sizeof(WORD);
152     mr->rdFunction = func;
153     mr->rdParm[0] = param5;
154     mr->rdParm[1] = param4;
155     mr->rdParm[2] = param3;
156     mr->rdParm[3] = param2;
157     mr->rdParm[4] = param1;
158     return metadc_record( hdc, mr, sizeof(buffer) );
159 }
160 
metadc_param6(HDC hdc,short func,short param1,short param2,short param3,short param4,short param5,short param6)161 static BOOL metadc_param6( HDC hdc, short func, short param1, short param2,
162                            short param3, short param4, short param5,
163                            short param6 )
164 {
165     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
166                    + 6*RTL_FIELD_SIZE(METARECORD, rdParm)];
167     METARECORD *mr = (METARECORD *)&buffer;
168 
169     mr->rdSize = sizeof(buffer) / sizeof(WORD);
170     mr->rdFunction = func;
171     mr->rdParm[0] = param6;
172     mr->rdParm[1] = param5;
173     mr->rdParm[2] = param4;
174     mr->rdParm[3] = param3;
175     mr->rdParm[4] = param2;
176     mr->rdParm[5] = param1;
177     return metadc_record( hdc, mr, sizeof(buffer) );
178 }
179 
metadc_param8(HDC hdc,short func,short param1,short param2,short param3,short param4,short param5,short param6,short param7,short param8)180 static BOOL metadc_param8( HDC hdc, short func, short param1, short param2,
181                            short param3, short param4, short param5,
182                            short param6, short param7, short param8)
183 {
184     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
185                    + 8*RTL_FIELD_SIZE(METARECORD, rdParm)];
186     METARECORD *mr = (METARECORD *)&buffer;
187 
188     mr->rdSize = sizeof(buffer) / sizeof(WORD);
189     mr->rdFunction = func;
190     mr->rdParm[0] = param8;
191     mr->rdParm[1] = param7;
192     mr->rdParm[2] = param6;
193     mr->rdParm[3] = param5;
194     mr->rdParm[4] = param4;
195     mr->rdParm[5] = param3;
196     mr->rdParm[6] = param2;
197     mr->rdParm[7] = param1;
198     return metadc_record( hdc, mr, sizeof(buffer) );
199 }
200 
METADC_SaveDC(HDC hdc)201 BOOL METADC_SaveDC( HDC hdc )
202 {
203     return metadc_param0( hdc, META_SAVEDC );
204 }
205 
METADC_RestoreDC(HDC hdc,INT level)206 BOOL METADC_RestoreDC( HDC hdc, INT level )
207 {
208     return metadc_param1( hdc, META_RESTOREDC, level );
209 }
210 
METADC_SetTextAlign(HDC hdc,UINT align)211 BOOL METADC_SetTextAlign( HDC hdc, UINT align )
212 {
213     return metadc_param2( hdc, META_SETTEXTALIGN, HIWORD(align), LOWORD(align) );
214 }
215 
METADC_SetBkMode(HDC hdc,INT mode)216 BOOL METADC_SetBkMode( HDC hdc, INT mode )
217 {
218     return metadc_param1( hdc, META_SETBKMODE, (WORD)mode );
219 }
220 
METADC_SetBkColor(HDC hdc,COLORREF color)221 BOOL METADC_SetBkColor( HDC hdc, COLORREF color )
222 {
223     return metadc_param2( hdc, META_SETBKCOLOR, HIWORD(color), LOWORD(color) );
224 }
225 
METADC_SetTextColor(HDC hdc,COLORREF color)226 BOOL METADC_SetTextColor( HDC hdc, COLORREF color )
227 {
228     return metadc_param2( hdc, META_SETTEXTCOLOR, HIWORD(color), LOWORD(color) );
229 }
230 
METADC_SetROP2(HDC hdc,INT rop)231 BOOL METADC_SetROP2( HDC hdc, INT rop )
232 {
233     return metadc_param1( hdc, META_SETROP2, (WORD)rop );
234 }
235 
METADC_SetRelAbs(HDC hdc,INT mode)236 BOOL METADC_SetRelAbs( HDC hdc, INT mode )
237 {
238     return metadc_param1( hdc, META_SETRELABS, (WORD)mode );
239 }
240 
METADC_SetPolyFillMode(HDC hdc,INT mode)241 BOOL METADC_SetPolyFillMode( HDC hdc, INT mode )
242 {
243     return metadc_param1( hdc, META_SETPOLYFILLMODE, mode );
244 }
245 
METADC_SetStretchBltMode(HDC hdc,INT mode)246 BOOL METADC_SetStretchBltMode( HDC hdc, INT mode )
247 {
248     return metadc_param1( hdc, META_SETSTRETCHBLTMODE, mode );
249 }
250 
METADC_IntersectClipRect(HDC hdc,INT left,INT top,INT right,INT bottom)251 BOOL METADC_IntersectClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
252 {
253     return metadc_param4( hdc, META_INTERSECTCLIPRECT, left, top, right, bottom );
254 }
255 
METADC_ExcludeClipRect(HDC hdc,INT left,INT top,INT right,INT bottom)256 BOOL METADC_ExcludeClipRect( HDC hdc, INT left, INT top, INT right, INT bottom )
257 {
258     return metadc_param4( hdc, META_EXCLUDECLIPRECT, left, top, right, bottom );
259 }
260 
METADC_OffsetClipRgn(HDC hdc,INT x,INT y)261 BOOL METADC_OffsetClipRgn( HDC hdc, INT x, INT y )
262 {
263     return metadc_param2( hdc, META_OFFSETCLIPRGN, x, y );
264 }
265 
METADC_SetLayout(HDC hdc,DWORD layout)266 BOOL METADC_SetLayout( HDC hdc, DWORD layout )
267 {
268     return metadc_param2( hdc, META_SETLAYOUT, HIWORD(layout), LOWORD(layout) );
269 }
270 
METADC_SetMapMode(HDC hdc,INT mode)271 BOOL METADC_SetMapMode( HDC hdc, INT mode )
272 {
273     return metadc_param1( hdc, META_SETMAPMODE, mode );
274 }
275 
METADC_SetViewportExtEx(HDC hdc,INT x,INT y)276 BOOL METADC_SetViewportExtEx( HDC hdc, INT x, INT y )
277 {
278     return metadc_param2( hdc, META_SETVIEWPORTEXT, x, y );
279 }
280 
METADC_SetViewportOrgEx(HDC hdc,INT x,INT y)281 BOOL METADC_SetViewportOrgEx( HDC hdc, INT x, INT y )
282 {
283     return metadc_param2( hdc, META_SETVIEWPORTORG, x, y );
284 }
285 
METADC_SetWindowExtEx(HDC hdc,INT x,INT y)286 BOOL METADC_SetWindowExtEx( HDC hdc, INT x, INT y )
287 {
288     return metadc_param2( hdc, META_SETWINDOWEXT, x, y );
289 }
290 
METADC_SetWindowOrgEx(HDC hdc,INT x,INT y)291 BOOL METADC_SetWindowOrgEx( HDC hdc, INT x, INT y )
292 {
293     return metadc_param2( hdc, META_SETWINDOWORG, x, y );
294 }
295 
METADC_OffsetViewportOrgEx(HDC hdc,INT x,INT y)296 BOOL METADC_OffsetViewportOrgEx( HDC hdc, INT x, INT y )
297 {
298     return metadc_param2( hdc, META_OFFSETVIEWPORTORG, x, y );
299 }
300 
METADC_OffsetWindowOrgEx(HDC hdc,INT x,INT y)301 BOOL METADC_OffsetWindowOrgEx( HDC hdc, INT x, INT y )
302 {
303     return metadc_param2( hdc, META_OFFSETWINDOWORG, x, y );
304 }
305 
METADC_ScaleViewportExtEx(HDC hdc,INT x_num,INT x_denom,INT y_num,INT y_denom)306 BOOL METADC_ScaleViewportExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
307 {
308     return metadc_param4( hdc, META_SCALEVIEWPORTEXT, x_num, x_denom, y_num, y_denom );
309 }
310 
METADC_ScaleWindowExtEx(HDC hdc,INT x_num,INT x_denom,INT y_num,INT y_denom)311 BOOL METADC_ScaleWindowExtEx( HDC hdc, INT x_num, INT x_denom, INT y_num, INT y_denom )
312 {
313     return metadc_param4( hdc, META_SCALEWINDOWEXT, x_num, x_denom, y_num, y_denom );
314 }
315 
METADC_SetTextJustification(HDC hdc,INT extra,INT breaks)316 BOOL METADC_SetTextJustification( HDC hdc, INT extra, INT breaks )
317 {
318     return metadc_param2( hdc, META_SETTEXTJUSTIFICATION, extra, breaks );
319 }
320 
METADC_SetTextCharacterExtra(HDC hdc,INT extra)321 BOOL METADC_SetTextCharacterExtra( HDC hdc, INT extra )
322 {
323     return metadc_param1( hdc, META_SETTEXTCHAREXTRA, extra );
324 }
325 
METADC_SetMapperFlags(HDC hdc,DWORD flags)326 BOOL METADC_SetMapperFlags( HDC hdc, DWORD flags )
327 {
328     return metadc_param2( hdc, META_SETMAPPERFLAGS, HIWORD(flags), LOWORD(flags) );
329 }
330 
METADC_MoveTo(HDC hdc,INT x,INT y)331 BOOL METADC_MoveTo( HDC hdc, INT x, INT y )
332 {
333     return metadc_param2( hdc, META_MOVETO, x, y );
334 }
335 
METADC_LineTo(HDC hdc,INT x,INT y)336 BOOL METADC_LineTo( HDC hdc, INT x, INT y )
337 {
338     return metadc_param2( hdc, META_LINETO, x, y );
339 }
340 
METADC_Arc(HDC hdc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)341 BOOL METADC_Arc( HDC hdc, INT left, INT top, INT right, INT bottom,
342                  INT xstart, INT ystart, INT xend, INT yend )
343 {
344      return metadc_param8( hdc, META_ARC, left, top, right, bottom,
345                            xstart, ystart, xend, yend );
346 }
347 
METADC_Pie(HDC hdc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)348 BOOL METADC_Pie( HDC hdc, INT left, INT top, INT right, INT bottom,
349                  INT xstart, INT ystart, INT xend, INT yend )
350 {
351     return metadc_param8( hdc, META_PIE, left, top, right, bottom,
352                           xstart, ystart, xend, yend );
353 }
354 
METADC_Chord(HDC hdc,INT left,INT top,INT right,INT bottom,INT xstart,INT ystart,INT xend,INT yend)355 BOOL METADC_Chord( HDC hdc, INT left, INT top, INT right, INT bottom,
356                    INT xstart, INT ystart, INT xend, INT yend )
357 {
358     return metadc_param8( hdc, META_CHORD, left, top, right, bottom,
359                           xstart, ystart, xend, yend );
360 }
361 
METADC_Ellipse(HDC hdc,INT left,INT top,INT right,INT bottom)362 BOOL METADC_Ellipse( HDC hdc, INT left, INT top, INT right, INT bottom )
363 {
364     return metadc_param4( hdc, META_ELLIPSE, left, top, right, bottom );
365 }
366 
METADC_Rectangle(HDC hdc,INT left,INT top,INT right,INT bottom)367 BOOL METADC_Rectangle( HDC hdc, INT left, INT top, INT right, INT bottom )
368 {
369     return metadc_param4( hdc, META_RECTANGLE, left, top, right, bottom );
370 }
371 
METADC_RoundRect(HDC hdc,INT left,INT top,INT right,INT bottom,INT ell_width,INT ell_height)372 BOOL METADC_RoundRect( HDC hdc, INT left, INT top, INT right,
373                        INT bottom, INT ell_width, INT ell_height )
374 {
375     return metadc_param6( hdc, META_ROUNDRECT, left, top, right, bottom,
376                           ell_width, ell_height );
377 }
378 
METADC_SetPixel(HDC hdc,INT x,INT y,COLORREF color)379 BOOL METADC_SetPixel( HDC hdc, INT x, INT y, COLORREF color )
380 {
381     return metadc_param4( hdc, META_SETPIXEL, x, y, HIWORD(color), LOWORD(color) );
382 }
383 
metadc_poly(HDC hdc,short func,POINTS * pt,short count)384 static BOOL metadc_poly( HDC hdc, short func, POINTS *pt, short count )
385 {
386     BOOL ret;
387     DWORD len;
388     METARECORD *mr;
389 
390     len = sizeof(METARECORD) + count * 4;
391     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
392         return FALSE;
393 
394     mr->rdSize = len / 2;
395     mr->rdFunction = func;
396     *(mr->rdParm) = count;
397     memcpy(mr->rdParm + 1, pt, count * 4);
398     ret = metadc_record( hdc, mr, mr->rdSize * 2);
399     HeapFree( GetProcessHeap(), 0, mr);
400     return ret;
401 }
402 
METADC_Polyline(HDC hdc,const POINT * pt,INT count)403 BOOL METADC_Polyline( HDC hdc, const POINT *pt, INT count )
404 {
405     int i;
406     POINTS *pts;
407     BOOL ret;
408 
409     pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
410     if(!pts) return FALSE;
411     for (i=count;i--;)
412     {
413         pts[i].x = pt[i].x;
414         pts[i].y = pt[i].y;
415     }
416     ret = metadc_poly( hdc, META_POLYLINE, pts, count );
417 
418     HeapFree( GetProcessHeap(), 0, pts );
419     return ret;
420 }
421 
METADC_Polygon(HDC hdc,const POINT * pt,INT count)422 BOOL METADC_Polygon( HDC hdc, const POINT *pt, INT count )
423 {
424     int i;
425     POINTS *pts;
426     BOOL ret;
427 
428     pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * count );
429     if(!pts) return FALSE;
430     for (i = count; i--;)
431     {
432         pts[i].x = pt[i].x;
433         pts[i].y = pt[i].y;
434     }
435     ret = metadc_poly( hdc, META_POLYGON, pts, count );
436 
437     HeapFree( GetProcessHeap(), 0, pts );
438     return ret;
439 }
440 
METADC_PolyPolygon(HDC hdc,const POINT * pt,const INT * counts,UINT polygons)441 BOOL METADC_PolyPolygon( HDC hdc, const POINT *pt, const INT *counts, UINT polygons )
442 {
443     BOOL ret;
444     DWORD len;
445     METARECORD *mr;
446     unsigned int i,j;
447     POINTS *pts;
448     INT16 totalpoint16 = 0;
449     INT16 * pointcounts;
450 
451     for (i = 0; i < polygons; i++)
452          totalpoint16 += counts[i];
453 
454     /* allocate space for all points */
455     pts=HeapAlloc( GetProcessHeap(), 0, sizeof(POINTS) * totalpoint16 );
456     pointcounts = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * totalpoint16 );
457 
458     /* copy point counts */
459     for (i = 0; i < polygons; i++)
460           pointcounts[i] = counts[i];
461 
462     /* convert all points */
463     for (j = totalpoint16; j--;)
464     {
465         pts[j].x = pt[j].x;
466         pts[j].y = pt[j].y;
467     }
468 
469     len = sizeof(METARECORD) + sizeof(WORD) + polygons * sizeof(INT16) +
470         totalpoint16 * sizeof(*pts);
471 
472     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
473     {
474          HeapFree( GetProcessHeap(), 0, pts );
475          HeapFree( GetProcessHeap(), 0, pointcounts );
476          return FALSE;
477     }
478 
479     mr->rdSize = len / sizeof(WORD);
480     mr->rdFunction = META_POLYPOLYGON;
481     *mr->rdParm = polygons;
482     memcpy( mr->rdParm + 1, pointcounts, polygons * sizeof(INT16) );
483     memcpy( mr->rdParm + 1+polygons, pts , totalpoint16 * sizeof(*pts) );
484     ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
485 
486     HeapFree( GetProcessHeap(), 0, pts );
487     HeapFree( GetProcessHeap(), 0, pointcounts );
488     HeapFree( GetProcessHeap(), 0, mr);
489     return ret;
490 }
491 
METADC_ExtFloodFill(HDC hdc,INT x,INT y,COLORREF color,UINT fill_type)492 BOOL METADC_ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color, UINT fill_type )
493 {
494     return metadc_param5( hdc, META_EXTFLOODFILL, x, y, HIWORD(color), LOWORD(color), fill_type );
495 }
496 
metadc_add_handle(struct metadc * metadc,HGDIOBJ obj)497 static UINT metadc_add_handle( struct metadc *metadc, HGDIOBJ obj )
498 {
499     UINT16 index;
500 
501     for (index = 0; index < metadc->handles_size; index++)
502         if (metadc->handles[index] == 0) break;
503     if(index == metadc->handles_size)
504     {
505         metadc->handles_size += HANDLE_LIST_INC;
506         metadc->handles = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
507                                        metadc->handles,
508                                        metadc->handles_size * sizeof(metadc->handles[0]) );
509     }
510     metadc->handles[index] = get_full_gdi_handle( obj );
511 
512     metadc->cur_handles++;
513     if (metadc->cur_handles > metadc->mh->mtNoObjects)
514         metadc->mh->mtNoObjects++;
515 
516     return index ; /* index 0 is not reserved for metafiles */
517 }
518 
metadc_remove_handle(struct metadc * metadc,UINT index)519 static BOOL metadc_remove_handle( struct metadc *metadc, UINT index )
520 {
521     BOOL ret = FALSE;
522 
523     if (index < metadc->handles_size && metadc->handles[index])
524     {
525         metadc->handles[index] = 0;
526         metadc->cur_handles--;
527         ret = TRUE;
528     }
529     return ret;
530 }
531 
metadc_create_brush(struct metadc * metadc,HBRUSH brush)532 static INT16 metadc_create_brush( struct metadc *metadc, HBRUSH brush )
533 {
534     DWORD size;
535     METARECORD *mr;
536     LOGBRUSH logbrush;
537     BOOL r;
538 
539     if (!GetObjectA( brush, sizeof(logbrush), &logbrush )) return -1;
540 
541     switch (logbrush.lbStyle)
542     {
543     case BS_SOLID:
544     case BS_NULL:
545     case BS_HATCHED:
546         {
547             LOGBRUSH16 lb16;
548 
549             lb16.lbStyle = logbrush.lbStyle;
550             lb16.lbColor = logbrush.lbColor;
551             lb16.lbHatch = logbrush.lbHatch;
552             size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - sizeof(WORD);
553             mr = HeapAlloc( GetProcessHeap(), 0, size );
554             mr->rdSize = size / sizeof(WORD);
555             mr->rdFunction = META_CREATEBRUSHINDIRECT;
556             memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16) );
557             break;
558         }
559     case BS_PATTERN:
560     case BS_DIBPATTERN:
561         {
562             unsigned char buffer[FIELD_OFFSET(BITMAPINFO, bmiColors)
563                          + 256*RTL_FIELD_SIZE(BITMAPINFO, bmiColors)];
564             BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
565             DWORD info_size;
566             UINT usage;
567 
568             if (!get_brush_bitmap_info( brush, src_info, NULL, &usage )) goto done;
569 
570             info_size = get_dib_info_size( src_info, usage );
571             size = FIELD_OFFSET( METARECORD, rdParm[2] ) +
572                 info_size + src_info->bmiHeader.biSizeImage;
573 
574             if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) goto done;
575             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
576             mr->rdSize = size / sizeof(WORD);
577             mr->rdParm[0] = logbrush.lbStyle;
578             mr->rdParm[1] = usage;
579             dst_info = (BITMAPINFO *)(mr->rdParm + 2);
580             get_brush_bitmap_info( brush, dst_info, (char *)dst_info + info_size, NULL );
581             if (dst_info->bmiHeader.biClrUsed == 1 << dst_info->bmiHeader.biBitCount)
582                 dst_info->bmiHeader.biClrUsed = 0;
583             break;
584         }
585 
586         default:
587             FIXME( "Unknown brush style %x\n", logbrush.lbStyle );
588             return 0;
589     }
590 
591     r = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
592     HeapFree(GetProcessHeap(), 0, mr);
593     if (!r) return -1;
594 done:
595     return metadc_add_handle( metadc, brush );
596 }
597 
metadc_create_region(struct metadc * metadc,HRGN hrgn)598 static INT16 metadc_create_region( struct metadc *metadc, HRGN hrgn )
599 {
600     DWORD len;
601     METARECORD *mr;
602     RGNDATA *rgndata;
603     RECT *cur_rect, *end_rect;
604     WORD bands = 0, max_bounds = 0;
605     WORD *param, *start_band;
606     BOOL ret;
607 
608     if (!(len = GetRegionData( hrgn, 0, NULL ))) return -1;
609     if (!(rgndata = HeapAlloc( GetProcessHeap(), 0, len )))
610     {
611         WARN( "Can't alloc rgndata buffer\n" );
612         return -1;
613     }
614     GetRegionData( hrgn, len, rgndata );
615 
616     /* Overestimate of length:
617      * Assume every rect is a separate band -> 6 WORDs per rect,
618      * see MF_Play_MetaCreateRegion for format details.
619      */
620     len = sizeof(METARECORD) + 20 + rgndata->rdh.nCount * 12;
621     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len )))
622     {
623         WARN( "Can't alloc METARECORD buffer\n" );
624         HeapFree( GetProcessHeap(), 0, rgndata );
625         return -1;
626     }
627 
628     param = mr->rdParm + 11;
629     start_band = NULL;
630 
631     end_rect = (RECT *)rgndata->Buffer + rgndata->rdh.nCount;
632     for (cur_rect = (RECT *)rgndata->Buffer; cur_rect < end_rect; cur_rect++)
633     {
634         if (start_band && cur_rect->top == start_band[1])
635         {
636             *param++ = cur_rect->left;
637             *param++ = cur_rect->right;
638         }
639         else
640         {
641             if (start_band)
642             {
643                 *start_band = param - start_band - 3;
644                 *param++ = *start_band;
645                 if (*start_band > max_bounds)
646                     max_bounds = *start_band;
647                 bands++;
648             }
649             start_band = param++;
650             *param++ = cur_rect->top;
651             *param++ = cur_rect->bottom;
652             *param++ = cur_rect->left;
653             *param++ = cur_rect->right;
654         }
655     }
656 
657     if (start_band)
658     {
659         *start_band = param - start_band - 3;
660         *param++ = *start_band;
661         if (*start_band > max_bounds)
662             max_bounds = *start_band;
663         bands++;
664     }
665 
666     mr->rdParm[0] = 0;
667     mr->rdParm[1] = 6;
668     mr->rdParm[2] = 0x2f6;
669     mr->rdParm[3] = 0;
670     mr->rdParm[4] = (WORD)((param - &mr->rdFunction) * sizeof(WORD));
671     mr->rdParm[5] = bands;
672     mr->rdParm[6] = max_bounds;
673     mr->rdParm[7] = rgndata->rdh.rcBound.left;
674     mr->rdParm[8] = rgndata->rdh.rcBound.top;
675     mr->rdParm[9] = rgndata->rdh.rcBound.right;
676     mr->rdParm[10] = rgndata->rdh.rcBound.bottom;
677     mr->rdFunction = META_CREATEREGION;
678     mr->rdSize = param - (WORD *)mr;
679     ret = metadc_write_record( metadc, mr, mr->rdSize * 2 );
680     HeapFree( GetProcessHeap(), 0, mr );
681     HeapFree( GetProcessHeap(), 0, rgndata );
682     if (!ret)
683     {
684         WARN("MFDRV_WriteRecord failed\n");
685         return -1;
686     }
687     return metadc_add_handle( metadc, hrgn );
688 }
689 
METADC_PaintRgn(HDC hdc,HRGN hrgn)690 BOOL METADC_PaintRgn( HDC hdc, HRGN hrgn )
691 {
692     struct metadc *metadc;
693     INT16 index;
694     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
695     index = metadc_create_region( metadc, hrgn );
696     if(index == -1) return FALSE;
697     return metadc_param1( hdc, META_PAINTREGION, index );
698 }
699 
METADC_InvertRgn(HDC hdc,HRGN hrgn)700 BOOL METADC_InvertRgn( HDC hdc, HRGN hrgn )
701 {
702     struct metadc *metadc;
703     INT16 index;
704     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
705     index = metadc_create_region( metadc, hrgn );
706     if (index == -1) return FALSE;
707     return metadc_param1( hdc, META_INVERTREGION, index );
708 }
709 
METADC_FillRgn(HDC hdc,HRGN hrgn,HBRUSH hbrush)710 BOOL METADC_FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
711 {
712     struct metadc *metadc;
713     INT16 rgn, brush;
714 
715     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
716 
717     rgn = metadc_create_region( metadc, hrgn );
718     if (rgn == -1) return FALSE;
719     brush = metadc_create_brush( metadc, hbrush );
720     if (!brush) return FALSE;
721     return metadc_param2( hdc, META_FILLREGION, rgn, brush );
722 }
723 
METADC_FrameRgn(HDC hdc,HRGN hrgn,HBRUSH hbrush,INT x,INT y)724 BOOL METADC_FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush, INT x, INT y )
725 {
726     struct metadc *metadc;
727     INT16 rgn, brush;
728 
729     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
730     rgn = metadc_create_region( metadc, hrgn );
731     if (rgn == -1) return FALSE;
732     brush = metadc_create_brush( metadc, hbrush );
733     if (!brush) return FALSE;
734     return metadc_param4( hdc, META_FRAMEREGION, rgn, brush, x, y );
735 }
736 
METADC_PatBlt(HDC hdc,INT left,INT top,INT width,INT height,DWORD rop)737 BOOL METADC_PatBlt( HDC hdc, INT left, INT top, INT width, INT height, DWORD rop )
738 {
739     return metadc_param6( hdc, META_PATBLT, left, top, width, height,
740                           HIWORD(rop), LOWORD(rop) );
741 }
742 
metadc_stretchblt(HDC hdc,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,INT width_src,INT height_src,DWORD rop,WORD type)743 static BOOL metadc_stretchblt( HDC hdc, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
744                                HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
745                                DWORD rop, WORD type )
746 {
747     BITMAPINFO src_info = {{ sizeof( src_info.bmiHeader ) }};
748     UINT bmi_size, size, bpp;
749     int i = 0, bitmap_offset;
750     BITMAPINFO *bmi;
751     METARECORD *mr;
752     HBITMAP bitmap;
753     BOOL ret;
754 
755     if (!(bitmap = GetCurrentObject( hdc_src, OBJ_BITMAP ))) return FALSE;
756     if (!GetDIBits( hdc_src, bitmap, 0, INT_MAX, NULL, &src_info, DIB_RGB_COLORS )) return FALSE;
757 
758     bpp = src_info.bmiHeader.biBitCount;
759     if (bpp <= 8)
760         bmi_size = sizeof(BITMAPINFOHEADER) + (1L << bpp) * sizeof(RGBQUAD);
761     else if (bpp == 16 || bpp == 32)
762         bmi_size = sizeof(BITMAPINFOHEADER) + 3 * sizeof(RGBQUAD);
763     else
764         bmi_size = sizeof(BITMAPINFOHEADER);
765 
766     bitmap_offset = type == META_DIBBITBLT ? 8 : 10;
767     size = FIELD_OFFSET( METARECORD, rdParm[bitmap_offset] ) + bmi_size +
768         src_info.bmiHeader.biSizeImage;
769     if (!(mr = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
770     mr->rdFunction = type;
771     bmi = (BITMAPINFO *)&mr->rdParm[bitmap_offset];
772     bmi->bmiHeader = src_info.bmiHeader;
773     TRACE( "size = %u  rop=%x\n", size, rop );
774 
775     ret = GetDIBits( hdc_src, bitmap, 0, src_info.bmiHeader.biHeight, (BYTE *)bmi + bmi_size,
776                      bmi, DIB_RGB_COLORS );
777     if (ret)
778     {
779         mr->rdSize = size / sizeof(WORD);
780         mr->rdParm[i++] = LOWORD(rop);
781         mr->rdParm[i++] = HIWORD(rop);
782         if (bitmap_offset > 8)
783         {
784             mr->rdParm[i++] = height_src;
785             mr->rdParm[i++] = width_src;
786         }
787         mr->rdParm[i++] = y_src;
788         mr->rdParm[i++] = x_src;
789         mr->rdParm[i++] = height_dst;
790         mr->rdParm[i++] = width_dst;
791         mr->rdParm[i++] = y_dst;
792         mr->rdParm[i++] = x_dst;
793         ret = metadc_record( hdc, mr, size );
794     }
795 
796     HeapFree( GetProcessHeap(), 0, mr);
797     return ret;
798 }
799 
METADC_BitBlt(HDC hdc,INT x_dst,INT y_dst,INT width,INT height,HDC hdc_src,INT x_src,INT y_src,DWORD rop)800 BOOL METADC_BitBlt( HDC hdc, INT x_dst, INT y_dst, INT width, INT height,
801                     HDC hdc_src, INT x_src, INT y_src, DWORD rop )
802 {
803     return metadc_stretchblt( hdc, x_dst, y_dst, width, height,
804                               hdc_src, x_src, y_src, width, height, rop, META_DIBBITBLT );
805 }
806 
METADC_StretchBlt(HDC hdc_dst,INT x_dst,INT y_dst,INT width_dst,INT height_dst,HDC hdc_src,INT x_src,INT y_src,INT width_src,INT height_src,DWORD rop)807 BOOL METADC_StretchBlt( HDC hdc_dst, INT x_dst, INT y_dst, INT width_dst, INT height_dst,
808                         HDC hdc_src, INT x_src, INT y_src, INT width_src, INT height_src,
809                         DWORD rop )
810 {
811     return metadc_stretchblt( hdc_dst, x_dst, y_dst, width_dst, height_dst,
812                               hdc_src, x_src, y_src, width_src, height_src, rop, META_DIBSTRETCHBLT );
813 }
814 
METADC_StretchDIBits(HDC hdc,INT x_dst,INT y_dst,INT width_dst,INT height_dst,INT x_src,INT y_src,INT width_src,INT height_src,const void * bits,const BITMAPINFO * info,UINT usage,DWORD rop)815 INT METADC_StretchDIBits( HDC hdc, INT x_dst, INT y_dst, INT width_dst,
816                           INT height_dst, INT x_src, INT y_src, INT width_src,
817                           INT height_src, const void *bits,
818                           const BITMAPINFO *info, UINT usage, DWORD rop )
819 {
820     DWORD infosize = get_dib_info_size( info, usage );
821     DWORD len = sizeof(METARECORD) + 10 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
822     METARECORD *mr;
823 
824     if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
825 
826     mr->rdSize = len / sizeof(WORD);
827     mr->rdFunction = META_STRETCHDIB;
828     mr->rdParm[0] = LOWORD(rop);
829     mr->rdParm[1] = HIWORD(rop);
830     mr->rdParm[2] = usage;
831     mr->rdParm[3] = height_src;
832     mr->rdParm[4] = width_src;
833     mr->rdParm[5] = y_src;
834     mr->rdParm[6] = x_src;
835     mr->rdParm[7] = height_dst;
836     mr->rdParm[8] = width_dst;
837     mr->rdParm[9] = y_dst;
838     mr->rdParm[10] = x_dst;
839     memcpy( mr->rdParm + 11, info, infosize );
840     memcpy( mr->rdParm + 11 + infosize / 2, bits, info->bmiHeader.biSizeImage );
841     metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
842     HeapFree( GetProcessHeap(), 0, mr );
843     return height_src;
844 }
845 
METADC_SetDIBitsToDevice(HDC hdc,INT x_dst,INT y_dst,DWORD width,DWORD height,INT x_src,INT y_src,UINT startscan,UINT lines,const void * bits,const BITMAPINFO * info,UINT coloruse)846 INT METADC_SetDIBitsToDevice( HDC hdc, INT x_dst, INT y_dst, DWORD width, DWORD height,
847                               INT x_src, INT y_src, UINT startscan, UINT lines,
848                               const void *bits, const BITMAPINFO *info, UINT coloruse )
849 
850 {
851     DWORD infosize = get_dib_info_size(info, coloruse);
852     DWORD len = sizeof(METARECORD) + 8 * sizeof(WORD) + infosize + info->bmiHeader.biSizeImage;
853     METARECORD *mr;
854 
855     if (!(mr = HeapAlloc( GetProcessHeap(), 0, len ))) return 0;
856 
857     mr->rdSize = len / sizeof(WORD);
858     mr->rdFunction = META_SETDIBTODEV;
859     mr->rdParm[0] = coloruse;
860     mr->rdParm[1] = lines;
861     mr->rdParm[2] = startscan;
862     mr->rdParm[3] = y_src;
863     mr->rdParm[4] = x_src;
864     mr->rdParm[5] = height;
865     mr->rdParm[6] = width;
866     mr->rdParm[7] = y_dst;
867     mr->rdParm[8] = x_dst;
868     memcpy( mr->rdParm + 9, info, infosize );
869     memcpy( mr->rdParm + 9 + infosize / sizeof(WORD), bits, info->bmiHeader.biSizeImage );
870     metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
871     HeapFree( GetProcessHeap(), 0, mr );
872     return lines;
873 }
874 
metadc_text(HDC hdc,short x,short y,UINT16 flags,const RECT16 * rect,const char * str,short count,const INT16 * dx)875 static BOOL metadc_text( HDC hdc, short x, short y, UINT16 flags, const RECT16 *rect,
876                          const char *str, short count, const INT16 *dx )
877 {
878     BOOL ret;
879     DWORD len;
880     METARECORD *mr;
881     BOOL isrect = flags & (ETO_CLIPPED | ETO_OPAQUE);
882 
883     len = sizeof(METARECORD) + (((count + 1) >> 1) * 2) + 2 * sizeof(short)
884             + sizeof(UINT16);
885     if (isrect) len += sizeof(RECT16);
886     if (dx) len += count * sizeof(INT16);
887     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
888 
889     mr->rdSize = len / sizeof(WORD);
890     mr->rdFunction = META_EXTTEXTOUT;
891     mr->rdParm[0] = y;
892     mr->rdParm[1] = x;
893     mr->rdParm[2] = count;
894     mr->rdParm[3] = flags;
895     if (isrect) memcpy( mr->rdParm + 4, rect, sizeof(RECT16) );
896     memcpy( mr->rdParm + (isrect ? 8 : 4), str, count );
897     if (dx)
898         memcpy( mr->rdParm + (isrect ? 8 : 4) + ((count + 1) >> 1), dx, count * sizeof(INT16) );
899     ret = metadc_record( hdc, mr, mr->rdSize * sizeof(WORD) );
900     HeapFree( GetProcessHeap(), 0, mr );
901     return ret;
902 }
903 
METADC_ExtTextOut(HDC hdc,INT x,INT y,UINT flags,const RECT * lprect,const WCHAR * str,UINT count,const INT * dx)904 BOOL METADC_ExtTextOut( HDC hdc, INT x, INT y, UINT flags, const RECT *lprect,
905                         const WCHAR *str, UINT count, const INT *dx )
906 {
907     RECT16 rect16;
908     LPINT16 lpdx16 = NULL;
909     BOOL ret;
910     unsigned int i, j;
911     char *ascii;
912     DWORD len;
913     CHARSETINFO csi;
914     int charset = GetTextCharset( hdc );
915     UINT cp = CP_ACP;
916 
917     if (TranslateCharsetInfo( ULongToPtr(charset), &csi, TCI_SRCCHARSET ))
918         cp = csi.ciACP;
919     else
920     {
921         switch(charset)
922         {
923         case OEM_CHARSET:
924             cp = GetOEMCP();
925             break;
926         case DEFAULT_CHARSET:
927             cp = GetACP();
928             break;
929 
930         case VISCII_CHARSET:
931         case TCVN_CHARSET:
932         case KOI8_CHARSET:
933         case ISO3_CHARSET:
934         case ISO4_CHARSET:
935         case ISO10_CHARSET:
936         case CELTIC_CHARSET:
937             /* FIXME: These have no place here, but because x11drv
938                enumerates fonts with these (made up) charsets some apps
939                might use them and then the FIXME below would become
940                annoying.  Now we could pick the intended codepage for
941                each of these, but since it's broken anyway we'll just
942                use CP_ACP and hope it'll go away...
943             */
944             cp = CP_ACP;
945             break;
946 
947         default:
948             FIXME("Can't find codepage for charset %d\n", charset);
949             break;
950         }
951     }
952 
953 
954     TRACE( "cp = %d\n", cp );
955     len = WideCharToMultiByte( cp, 0, str, count, NULL, 0, NULL, NULL );
956     ascii = HeapAlloc( GetProcessHeap(), 0, len );
957     WideCharToMultiByte( cp, 0, str, count, ascii, len, NULL, NULL );
958     TRACE( "mapped %s -> %s\n", debugstr_wn(str, count), debugstr_an(ascii, len) );
959 
960 
961     if (lprect)
962     {
963         rect16.left   = lprect->left;
964         rect16.top    = lprect->top;
965         rect16.right  = lprect->right;
966         rect16.bottom = lprect->bottom;
967     }
968 
969     if (dx)
970     {
971         lpdx16 = HeapAlloc( GetProcessHeap(), 0, sizeof(INT16) * len );
972         for (i = j = 0; i < len; )
973             if (IsDBCSLeadByteEx( cp, ascii[i] ))
974             {
975                 lpdx16[i++] = dx[j++];
976                 lpdx16[i++] = 0;
977             }
978             else
979                 lpdx16[i++] = dx[j++];
980     }
981 
982     ret = metadc_text( hdc, x, y, flags, lprect ? &rect16 : NULL, ascii, len, lpdx16 );
983     HeapFree( GetProcessHeap(), 0, ascii );
984     HeapFree( GetProcessHeap(), 0, lpdx16 );
985     return ret;
986 }
987 
METADC_ExtSelectClipRgn(HDC hdc,HRGN hrgn,INT mode)988 BOOL METADC_ExtSelectClipRgn( HDC hdc, HRGN hrgn, INT mode )
989 {
990     struct metadc *metadc;
991     INT16 rgn;
992     INT ret;
993 
994     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
995     if (mode != RGN_COPY) return ERROR;
996     if (!hrgn) return NULLREGION;
997     rgn = metadc_create_region( metadc, hrgn );
998     if(rgn == -1) return ERROR;
999     ret = metadc_param1( hdc, META_SELECTOBJECT, rgn ) ? NULLREGION : ERROR;
1000     metadc_param1( hdc, META_DELETEOBJECT, rgn );
1001     metadc_remove_handle( metadc, rgn );
1002     return ret;
1003 }
1004 
metadc_find_object(struct metadc * metadc,HGDIOBJ obj)1005 static INT16 metadc_find_object( struct metadc *metadc, HGDIOBJ obj )
1006 {
1007     INT16 index;
1008 
1009     for (index = 0; index < metadc->handles_size; index++)
1010         if (metadc->handles[index] == obj) return index;
1011 
1012     return -1;
1013 }
1014 
METADC_DeleteObject(HDC hdc,HGDIOBJ obj)1015 void METADC_DeleteObject( HDC hdc, HGDIOBJ obj )
1016 {
1017     struct metadc *metadc = get_metadc_ptr( hdc );
1018     METARECORD mr;
1019     INT16 index;
1020 
1021     if ((index = metadc_find_object( metadc, obj )) < 0) return;
1022     if (obj == metadc->pen || obj == metadc->brush || obj == metadc->font)
1023     {
1024         WARN( "deleting selected object %p\n", obj );
1025         return;
1026     }
1027 
1028     mr.rdSize = sizeof(mr) / sizeof(WORD);
1029     mr.rdFunction = META_DELETEOBJECT;
1030     mr.rdParm[0] = index;
1031 
1032     metadc_write_record( metadc, &mr, mr.rdSize * sizeof(WORD) );
1033 
1034     metadc->handles[index] = 0;
1035     metadc->cur_handles--;
1036 }
1037 
metadc_select_object(HDC hdc,INT16 index)1038 static BOOL metadc_select_object( HDC hdc, INT16 index)
1039 {
1040     METARECORD mr;
1041 
1042     mr.rdSize = sizeof mr / 2;
1043     mr.rdFunction = META_SELECTOBJECT;
1044     mr.rdParm[0] = index;
1045     return metadc_record( hdc, &mr, mr.rdSize * sizeof(WORD) );
1046 }
1047 
METADC_SelectBrush(HDC hdc,HBRUSH hbrush)1048 static HBRUSH METADC_SelectBrush( HDC hdc, HBRUSH hbrush )
1049 {
1050     struct metadc *metadc = get_metadc_ptr( hdc );
1051     INT16 index;
1052     HBRUSH ret;
1053 
1054     index = metadc_find_object( metadc, hbrush );
1055     if( index < 0 )
1056     {
1057         index = metadc_create_brush( metadc, hbrush );
1058         if( index < 0 )
1059             return 0;
1060         GDI_hdc_using_object( hbrush, hdc );//, METADC_DeleteObject );
1061     }
1062     if (!metadc_select_object( hdc, index )) return 0;
1063     ret = metadc->brush;
1064     metadc->brush = hbrush;
1065     return ret;
1066 }
1067 
metadc_create_font(struct metadc * metadc,HFONT font,LOGFONTW * logfont)1068 static UINT16 metadc_create_font( struct metadc *metadc, HFONT font, LOGFONTW *logfont )
1069 {
1070     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm) + sizeof(LOGFONT16)];
1071     METARECORD *mr = (METARECORD *)&buffer;
1072     LOGFONT16 *font16;
1073     INT written;
1074 
1075     mr->rdSize = sizeof(buffer) / sizeof(WORD);
1076     mr->rdFunction = META_CREATEFONTINDIRECT;
1077     font16 = (LOGFONT16 *)&mr->rdParm;
1078 
1079     font16->lfHeight         = logfont->lfHeight;
1080     font16->lfWidth          = logfont->lfWidth;
1081     font16->lfEscapement     = logfont->lfEscapement;
1082     font16->lfOrientation    = logfont->lfOrientation;
1083     font16->lfWeight         = logfont->lfWeight;
1084     font16->lfItalic         = logfont->lfItalic;
1085     font16->lfUnderline      = logfont->lfUnderline;
1086     font16->lfStrikeOut      = logfont->lfStrikeOut;
1087     font16->lfCharSet        = logfont->lfCharSet;
1088     font16->lfOutPrecision   = logfont->lfOutPrecision;
1089     font16->lfClipPrecision  = logfont->lfClipPrecision;
1090     font16->lfQuality        = logfont->lfQuality;
1091     font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
1092     written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName,
1093                                    LF_FACESIZE - 1, NULL, NULL );
1094     /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
1095     memset( font16->lfFaceName + written, 0, LF_FACESIZE - written );
1096 
1097     if (!metadc_write_record( metadc, mr, mr->rdSize * 2 ))
1098         return 0;
1099     return metadc_add_handle( metadc, font );
1100 }
1101 
METADC_SelectFont(HDC hdc,HFONT hfont)1102 static HFONT METADC_SelectFont( HDC hdc, HFONT hfont )
1103 {
1104     struct metadc *metadc = get_metadc_ptr( hdc );
1105     LOGFONTW font;
1106     INT16 index;
1107     HFONT ret;
1108 
1109     index = metadc_find_object( metadc, hfont );
1110     if (index < 0)
1111     {
1112         if (!GetObjectW( hfont, sizeof(font), &font ))
1113             return 0;
1114         index = metadc_create_font( metadc, hfont, &font );
1115         if( index < 0 )
1116             return 0;
1117         GDI_hdc_using_object( hfont, hdc );//, METADC_DeleteObject );
1118     }
1119     if (!metadc_select_object( hdc, index )) return 0;
1120     ret = metadc->font;
1121     metadc->font = hfont;
1122     return ret;
1123 }
1124 
metadc_create_pen(struct metadc * metadc,HPEN pen,LOGPEN16 * logpen)1125 static UINT16 metadc_create_pen( struct metadc *metadc, HPEN pen, LOGPEN16 *logpen )
1126 {
1127     unsigned char buffer[FIELD_OFFSET(METARECORD, rdParm)
1128         + (sizeof(*logpen) / sizeof(WORD)) * RTL_FIELD_SIZE(METARECORD, rdParm)];
1129     METARECORD *mr = (METARECORD *)&buffer;
1130 
1131     mr->rdSize = sizeof(buffer) / sizeof(WORD);
1132     mr->rdFunction = META_CREATEPENINDIRECT;
1133     memcpy( mr->rdParm, logpen, sizeof(*logpen) );
1134     if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) )) return 0;
1135     return metadc_add_handle( metadc, pen );
1136 }
1137 
METADC_SelectPen(HDC hdc,HPEN hpen)1138 static HPEN METADC_SelectPen( HDC hdc, HPEN hpen )
1139 {
1140     struct metadc *metadc = get_metadc_ptr( hdc );
1141     LOGPEN16 logpen;
1142     INT16 index;
1143     HPEN ret;
1144 
1145     index = metadc_find_object( metadc, hpen );
1146     if (index < 0)
1147     {
1148         /* must be an extended pen */
1149         INT size = GetObjectW( hpen, 0, NULL );
1150 
1151         if (!size) return 0;
1152 
1153         if (size == sizeof(LOGPEN))
1154         {
1155             LOGPEN pen;
1156 
1157             GetObjectW( hpen, sizeof(pen), &pen );
1158             logpen.lopnStyle   = pen.lopnStyle;
1159             logpen.lopnWidth.x = pen.lopnWidth.x;
1160             logpen.lopnWidth.y = pen.lopnWidth.y;
1161             logpen.lopnColor   = pen.lopnColor;
1162         }
1163         else  /* must be an extended pen */
1164         {
1165             EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
1166 
1167             GetObjectW( hpen, size, elp );
1168             /* FIXME: add support for user style pens */
1169             logpen.lopnStyle = elp->elpPenStyle;
1170             logpen.lopnWidth.x = elp->elpWidth;
1171             logpen.lopnWidth.y = 0;
1172             logpen.lopnColor = elp->elpColor;
1173 
1174             HeapFree( GetProcessHeap(), 0, elp );
1175         }
1176 
1177         index = metadc_create_pen( metadc, hpen, &logpen );
1178         if( index < 0 )
1179             return 0;
1180         GDI_hdc_using_object( hpen, hdc );//, METADC_DeleteObject );
1181     }
1182 
1183     if (!metadc_select_object( hdc, index )) return 0;
1184     ret = metadc->pen;
1185     metadc->pen = hpen;
1186     return ret;
1187 }
1188 
metadc_create_palette(struct metadc * metadc,HPALETTE palette,LOGPALETTE * log_palette,int sizeofPalette)1189 static BOOL metadc_create_palette( struct metadc *metadc, HPALETTE palette,
1190                                    LOGPALETTE *log_palette, int sizeofPalette )
1191 {
1192     int index;
1193     BOOL ret;
1194     METARECORD *mr;
1195 
1196     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
1197     if (!mr) return FALSE;
1198     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
1199     mr->rdFunction = META_CREATEPALETTE;
1200     memcpy(&(mr->rdParm), log_palette, sizeofPalette);
1201     if (!metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) ))
1202     {
1203         HeapFree(GetProcessHeap(), 0, mr);
1204         return FALSE;
1205     }
1206 
1207     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
1208     mr->rdFunction = META_SELECTPALETTE;
1209 
1210     if ((index = metadc_add_handle( metadc, palette )) == -1) ret = FALSE;
1211     else
1212     {
1213         mr->rdParm[0] = index;
1214         ret = metadc_write_record( metadc, mr, mr->rdSize * sizeof(WORD) );
1215     }
1216     HeapFree( GetProcessHeap(), 0, mr );
1217     return ret;
1218 }
1219 
METADC_SelectPalette(HDC hdc,HPALETTE palette)1220 BOOL METADC_SelectPalette( HDC hdc, HPALETTE palette )
1221 {
1222     struct metadc *metadc;
1223     PLOGPALETTE log_palette;
1224     WORD count = 0;
1225     BOOL  ret;
1226     int size;
1227 
1228     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1229     GetObjectA( palette, sizeof(WORD), &count );
1230     if (!count) return 0;
1231 
1232     size = sizeof(LOGPALETTE) + (count - 1) * sizeof(PALETTEENTRY);
1233     log_palette = HeapAlloc( GetProcessHeap(), 0, size );
1234     if (!log_palette) return 0;
1235 
1236     log_palette->palVersion = 0x300;
1237     log_palette->palNumEntries = count;
1238 
1239     GetPaletteEntries( palette, 0, count, log_palette->palPalEntry );
1240 
1241     ret = metadc_create_palette( metadc, palette, log_palette, size );
1242 
1243     HeapFree( GetProcessHeap(), 0, log_palette );
1244     return ret;
1245 }
1246 
METADC_RealizePalette(HDC hdc)1247 BOOL METADC_RealizePalette( HDC hdc )
1248 {
1249     return metadc_param0( hdc, META_REALIZEPALETTE );
1250 }
1251 
METADC_SelectObject(HDC hdc,HGDIOBJ obj)1252 HGDIOBJ METADC_SelectObject( HDC hdc, HGDIOBJ obj )
1253 {
1254     switch (GDI_HANDLE_GET_TYPE( obj ))
1255     {
1256     case GDILoObjType_LO_BRUSH_TYPE:
1257         return METADC_SelectBrush( hdc, obj );
1258     case GDILoObjType_LO_FONT_TYPE:
1259         return METADC_SelectFont( hdc, obj );
1260     case GDILoObjType_LO_PEN_TYPE:
1261     case GDILoObjType_LO_EXTPEN_TYPE:
1262         return METADC_SelectPen( hdc, obj );
1263     default:
1264         SetLastError( ERROR_INVALID_FUNCTION );
1265         return 0;
1266     }
1267 }
1268 
METADC_ExtEscape(HDC hdc,INT escape,INT input_size,LPCSTR input,INT output_size,LPVOID output)1269 BOOL METADC_ExtEscape( HDC hdc, INT escape, INT input_size, LPCSTR input, INT output_size, LPVOID output )
1270 {
1271     METARECORD *mr;
1272     DWORD len;
1273     BOOL ret;
1274 
1275     if (output_size) return FALSE;  /* escapes that require output cannot work in metafiles */
1276 
1277     len = sizeof(*mr) + sizeof(WORD) + ((input_size + 1) & ~1);
1278     if (!(mr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len ))) return FALSE;
1279     mr->rdSize = len / sizeof(WORD);
1280     mr->rdFunction = META_ESCAPE;
1281     mr->rdParm[0] = escape;
1282     mr->rdParm[1] = input_size;
1283     memcpy( &mr->rdParm[2], input, input_size );
1284     ret = metadc_record( hdc, mr, len );
1285     HeapFree(GetProcessHeap(), 0, mr);
1286     return ret;
1287 }
1288 
METADC_GetDeviceCaps(HDC hdc,INT cap)1289 INT METADC_GetDeviceCaps( HDC hdc, INT cap )
1290 {
1291     if (!get_metadc_ptr( hdc )) return 0;
1292 
1293     switch(cap)
1294     {
1295     case TECHNOLOGY:
1296         return DT_METAFILE;
1297     case TEXTCAPS:
1298         return 0;
1299     default:
1300         TRACE(" unsupported capability %d, will return 0\n", cap );
1301     }
1302     return 0;
1303 }
1304 
metadc_free(struct metadc * metadc)1305 static void metadc_free( struct metadc *metadc )
1306 {
1307     DWORD index;
1308 
1309     CloseHandle( metadc->hFile );
1310     HeapFree( GetProcessHeap(), 0, metadc->mh );
1311     for(index = 0; index < metadc->handles_size; index++)
1312         if(metadc->handles[index])
1313             GDI_hdc_not_using_object( metadc->handles[index], metadc->hdc );
1314     HeapFree( GetProcessHeap(), 0, metadc->handles );
1315     HeapFree( GetProcessHeap(), 0, metadc );
1316 }
1317 
METADC_DeleteDC(HDC hdc)1318 BOOL METADC_DeleteDC( HDC hdc )
1319 {
1320     struct metadc *metadc;
1321 
1322     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1323     if (!GdiDeleteClientObj( hdc )) return FALSE;
1324     metadc_free( metadc );
1325     return TRUE;
1326 }
1327 
1328 /**********************************************************************
1329  *           CreateMetaFileW   (GDI32.@)
1330  *
1331  *  Create a new DC and associate it with a metafile. Pass a filename
1332  *  to create a disk-based metafile, NULL to create a memory metafile.
1333  */
CreateMetaFileW(const WCHAR * filename)1334 HDC WINAPI CreateMetaFileW( const WCHAR *filename )
1335 {
1336     struct metadc *metadc;
1337     HANDLE hdc;
1338 
1339     TRACE( "%s\n", debugstr_w(filename) );
1340 
1341     metadc = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc) );
1342     if (!metadc)
1343     {
1344         return NULL;
1345     }
1346     if (!(metadc->mh = HeapAlloc( GetProcessHeap(), 0, sizeof(*metadc->mh) )))
1347     {
1348         HeapFree( GetProcessHeap(), 0, metadc );
1349         return NULL;
1350     }
1351 
1352     if (!(hdc = GdiCreateClientObj( metadc, GDILoObjType_LO_METADC16_TYPE )))
1353     {
1354         HeapFree( GetProcessHeap(), 0, metadc );
1355         return NULL;
1356     }
1357 
1358     metadc->hdc = hdc;
1359 
1360     metadc->handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
1361                                  HANDLE_LIST_INC * sizeof(metadc->handles[0]) );
1362     metadc->handles_size = HANDLE_LIST_INC;
1363     metadc->cur_handles = 0;
1364 
1365     metadc->hFile = 0;
1366 
1367     metadc->mh->mtHeaderSize   = sizeof(METAHEADER) / sizeof(WORD);
1368     metadc->mh->mtVersion      = 0x0300;
1369     metadc->mh->mtSize         = metadc->mh->mtHeaderSize;
1370     metadc->mh->mtNoObjects    = 0;
1371     metadc->mh->mtMaxRecord    = 0;
1372     metadc->mh->mtNoParameters = 0;
1373     metadc->mh->mtType         = METAFILE_MEMORY;
1374 
1375     metadc->pen   = GetStockObject( BLACK_PEN );
1376     metadc->brush = GetStockObject( WHITE_BRUSH );
1377     metadc->font  = GetStockObject( DEVICE_DEFAULT_FONT );
1378 
1379     SetVirtualResolution( hdc, 0, 0, 0, 0);
1380 
1381     if (filename)  /* disk based metafile */
1382     {
1383         HANDLE file = CreateFileW( filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
1384         if (file == INVALID_HANDLE_VALUE)
1385         {
1386             HeapFree( GetProcessHeap(), 0, metadc );
1387             GdiDeleteClientObj( hdc );
1388             return 0;
1389         }
1390         metadc->hFile = file;
1391     }
1392 
1393     TRACE( "returning %p\n", hdc );
1394     return hdc;
1395 }
1396 
1397 /**********************************************************************
1398  *           CreateMetaFileA   (GDI32.@)
1399  */
CreateMetaFileA(const char * filename)1400 HDC WINAPI CreateMetaFileA( const char *filename )
1401 {
1402     LPWSTR filenameW;
1403     DWORD len;
1404     HDC hdc;
1405 
1406     if (!filename) return CreateMetaFileW( NULL );
1407 
1408     len = MultiByteToWideChar( CP_ACP, 0, filename, -1, NULL, 0 );
1409     filenameW = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1410     MultiByteToWideChar( CP_ACP, 0, filename, -1, filenameW, len );
1411 
1412     hdc = CreateMetaFileW( filenameW );
1413 
1414     HeapFree( GetProcessHeap(), 0, filenameW );
1415     return hdc;
1416 }
1417 
1418 /******************************************************************
1419  *           CloseMetaFile   (GDI32.@)
1420  *
1421  *  Stop recording graphics operations in metafile associated with
1422  *  hdc and retrieve metafile.
1423  */
CloseMetaFile(HDC hdc)1424 HMETAFILE WINAPI CloseMetaFile( HDC hdc )
1425 {
1426     struct metadc *metadc;
1427     DWORD bytes_written;
1428     HMETAFILE hmf;
1429 
1430     TRACE( "(%p)\n", hdc );
1431 
1432     if (!(metadc = get_metadc_ptr( hdc ))) return FALSE;
1433 
1434     /* Construct the end of metafile record - this is documented
1435      * in SDK Knowledgebase Q99334.
1436      */
1437     if (!metadc_param0( hdc, META_EOF )) return FALSE;
1438     if (!GdiDeleteClientObj( hdc )) return FALSE;
1439 
1440     if (metadc->hFile && !WriteFile( metadc->hFile, metadc->mh, metadc->mh->mtSize * sizeof(WORD),
1441                                      &bytes_written, NULL ))
1442     {
1443         metadc_free( metadc );
1444         return FALSE;
1445     }
1446 
1447     /* Now allocate a global handle for the metafile */
1448     hmf = MF_Create_HMETAFILE( metadc->mh );
1449     if (hmf) metadc->mh = NULL;  /* So it won't be deleted */
1450     metadc_free( metadc );
1451     return hmf;
1452 }
1453