msvcrt: Added _swscanf_l implementation.
[wine] / dlls / gdi32 / enhmfdrv / graphics.c
1 /*
2  * Enhanced MetaFile driver graphics functions
3  *
4  * Copyright 1999 Huw D M Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "enhmfdrv/enhmetafiledrv.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
35
36 /**********************************************************************
37  *           EMFDRV_MoveTo
38  */
39 BOOL CDECL
40 EMFDRV_MoveTo(PHYSDEV dev, INT x, INT y)
41 {
42     EMRMOVETOEX emr;
43
44     emr.emr.iType = EMR_MOVETOEX;
45     emr.emr.nSize = sizeof(emr);
46     emr.ptl.x = x;
47     emr.ptl.y = y;
48
49     return EMFDRV_WriteRecord( dev, &emr.emr );
50 }
51
52 /***********************************************************************
53  *           EMFDRV_LineTo
54  */
55 BOOL CDECL
56 EMFDRV_LineTo( PHYSDEV dev, INT x, INT y )
57 {
58     POINT pt;
59     EMRLINETO emr;
60     RECTL bounds;
61     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
62
63     emr.emr.iType = EMR_LINETO;
64     emr.emr.nSize = sizeof(emr);
65     emr.ptl.x = x;
66     emr.ptl.y = y;
67
68     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
69         return FALSE;
70
71     GetCurrentPositionEx(physDev->hdc, &pt);
72
73     bounds.left   = min(x, pt.x);
74     bounds.top    = min(y, pt.y);
75     bounds.right  = max(x, pt.x);
76     bounds.bottom = max(y, pt.y);
77
78     EMFDRV_UpdateBBox( dev, &bounds );
79
80     return TRUE;
81 }
82
83
84 /***********************************************************************
85  *           EMFDRV_ArcChordPie
86  */
87 static BOOL
88 EMFDRV_ArcChordPie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
89                     INT xstart, INT ystart, INT xend, INT yend, DWORD iType )
90 {
91     INT temp, xCentre, yCentre, i;
92     double angleStart, angleEnd;
93     double xinterStart, yinterStart, xinterEnd, yinterEnd;
94     EMRARC emr;
95     RECTL bounds;
96     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
97
98     if(left == right || top == bottom) return FALSE;
99
100     if(left > right) {temp = left; left = right; right = temp;}
101     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
102
103     if(GetGraphicsMode(physDev->hdc) == GM_COMPATIBLE) {
104         right--;
105         bottom--;
106     }
107
108     emr.emr.iType     = iType;
109     emr.emr.nSize     = sizeof(emr);
110     emr.rclBox.left   = left;
111     emr.rclBox.top    = top;
112     emr.rclBox.right  = right;
113     emr.rclBox.bottom = bottom;
114     emr.ptlStart.x    = xstart;
115     emr.ptlStart.y    = ystart;
116     emr.ptlEnd.x      = xend;
117     emr.ptlEnd.x      = yend;
118
119
120     /* Now calculate the BBox */
121     xCentre = (left + right + 1) / 2;
122     yCentre = (top + bottom + 1) / 2;
123
124     xstart -= xCentre;
125     ystart -= yCentre;
126     xend   -= xCentre;
127     yend   -= yCentre;
128
129     /* invert y co-ords to get angle anti-clockwise from x-axis */
130     angleStart = atan2( -(double)ystart, (double)xstart);
131     angleEnd   = atan2( -(double)yend, (double)xend);
132
133     /* These are the intercepts of the start/end lines with the arc */
134
135     xinterStart = (right - left + 1)/2 * cos(angleStart) + xCentre;
136     yinterStart = -(bottom - top + 1)/2 * sin(angleStart) + yCentre;
137     xinterEnd   = (right - left + 1)/2 * cos(angleEnd) + xCentre;
138     yinterEnd   = -(bottom - top + 1)/2 * sin(angleEnd) + yCentre;
139
140     if(angleStart < 0) angleStart += 2 * M_PI;
141     if(angleEnd < 0) angleEnd += 2 * M_PI;
142     if(angleEnd < angleStart) angleEnd += 2 * M_PI;
143
144     bounds.left   = min(xinterStart, xinterEnd);
145     bounds.top    = min(yinterStart, yinterEnd);
146     bounds.right  = max(xinterStart, xinterEnd);
147     bounds.bottom = max(yinterStart, yinterEnd);
148
149     for(i = 0; i <= 8; i++) {
150         if(i * M_PI / 2 < angleStart) /* loop until we're past start */
151             continue;
152         if(i * M_PI / 2 > angleEnd)   /* if we're past end we're finished */
153             break;
154
155         /* the arc touches the rectangle at the start of quadrant i, so adjust
156            BBox to reflect this. */
157
158         switch(i % 4) {
159         case 0:
160             bounds.right = right;
161             break;
162         case 1:
163             bounds.top = top;
164             break;
165         case 2:
166             bounds.left = left;
167             break;
168         case 3:
169             bounds.bottom = bottom;
170             break;
171         }
172     }
173
174     /* If we're drawing a pie then make sure we include the centre */
175     if(iType == EMR_PIE) {
176         if(bounds.left > xCentre) bounds.left = xCentre;
177         else if(bounds.right < xCentre) bounds.right = xCentre;
178         if(bounds.top > yCentre) bounds.top = yCentre;
179         else if(bounds.bottom < yCentre) bounds.right = yCentre;
180     }
181     if(!EMFDRV_WriteRecord( dev, &emr.emr ))
182         return FALSE;
183     EMFDRV_UpdateBBox( dev, &bounds );
184     return TRUE;
185 }
186
187
188 /***********************************************************************
189  *           EMFDRV_Arc
190  */
191 BOOL CDECL
192 EMFDRV_Arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
193             INT xstart, INT ystart, INT xend, INT yend )
194 {
195     return EMFDRV_ArcChordPie( dev, left, top, right, bottom, xstart, ystart,
196                                xend, yend, EMR_ARC );
197 }
198
199 /***********************************************************************
200  *           EMFDRV_Pie
201  */
202 BOOL CDECL
203 EMFDRV_Pie( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
204             INT xstart, INT ystart, INT xend, INT yend )
205 {
206     return EMFDRV_ArcChordPie( dev, left, top, right, bottom, xstart, ystart,
207                                xend, yend, EMR_PIE );
208 }
209
210
211 /***********************************************************************
212  *           EMFDRV_Chord
213  */
214 BOOL CDECL
215 EMFDRV_Chord( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
216              INT xstart, INT ystart, INT xend, INT yend )
217 {
218     return EMFDRV_ArcChordPie( dev, left, top, right, bottom, xstart, ystart,
219                                xend, yend, EMR_CHORD );
220 }
221
222 /***********************************************************************
223  *           EMFDRV_Ellipse
224  */
225 BOOL CDECL
226 EMFDRV_Ellipse( PHYSDEV dev, INT left, INT top, INT right, INT bottom )
227 {
228     EMRELLIPSE emr;
229     INT temp;
230     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
231
232     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
233
234     if(left == right || top == bottom) return FALSE;
235
236     if(left > right) {temp = left; left = right; right = temp;}
237     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
238
239     if(GetGraphicsMode(physDev->hdc) == GM_COMPATIBLE) {
240         right--;
241         bottom--;
242     }
243
244     emr.emr.iType     = EMR_ELLIPSE;
245     emr.emr.nSize     = sizeof(emr);
246     emr.rclBox.left   = left;
247     emr.rclBox.top    = top;
248     emr.rclBox.right  = right;
249     emr.rclBox.bottom = bottom;
250
251     EMFDRV_UpdateBBox( dev, &emr.rclBox );
252     return EMFDRV_WriteRecord( dev, &emr.emr );
253 }
254
255 /***********************************************************************
256  *           EMFDRV_Rectangle
257  */
258 BOOL CDECL
259 EMFDRV_Rectangle(PHYSDEV dev, INT left, INT top, INT right, INT bottom)
260 {
261     EMRRECTANGLE emr;
262     INT temp;
263     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
264
265     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
266
267     if(left == right || top == bottom) return FALSE;
268
269     if(left > right) {temp = left; left = right; right = temp;}
270     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
271
272     if(GetGraphicsMode(physDev->hdc) == GM_COMPATIBLE) {
273         right--;
274         bottom--;
275     }
276
277     emr.emr.iType     = EMR_RECTANGLE;
278     emr.emr.nSize     = sizeof(emr);
279     emr.rclBox.left   = left;
280     emr.rclBox.top    = top;
281     emr.rclBox.right  = right;
282     emr.rclBox.bottom = bottom;
283
284     EMFDRV_UpdateBBox( dev, &emr.rclBox );
285     return EMFDRV_WriteRecord( dev, &emr.emr );
286 }
287
288 /***********************************************************************
289  *           EMFDRV_RoundRect
290  */
291 BOOL CDECL
292 EMFDRV_RoundRect( PHYSDEV dev, INT left, INT top, INT right,
293                   INT bottom, INT ell_width, INT ell_height )
294 {
295     EMRROUNDRECT emr;
296     INT temp;
297     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
298
299     if(left == right || top == bottom) return FALSE;
300
301     if(left > right) {temp = left; left = right; right = temp;}
302     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
303
304     if(GetGraphicsMode(physDev->hdc) == GM_COMPATIBLE) {
305         right--;
306         bottom--;
307     }
308
309     emr.emr.iType     = EMR_ROUNDRECT;
310     emr.emr.nSize     = sizeof(emr);
311     emr.rclBox.left   = left;
312     emr.rclBox.top    = top;
313     emr.rclBox.right  = right;
314     emr.rclBox.bottom = bottom;
315     emr.szlCorner.cx  = ell_width;
316     emr.szlCorner.cy  = ell_height;
317
318     EMFDRV_UpdateBBox( dev, &emr.rclBox );
319     return EMFDRV_WriteRecord( dev, &emr.emr );
320 }
321
322 /***********************************************************************
323  *           EMFDRV_SetPixel
324  */
325 COLORREF CDECL
326 EMFDRV_SetPixel( PHYSDEV dev, INT x, INT y, COLORREF color )
327 {
328     EMRSETPIXELV emr;
329
330     emr.emr.iType  = EMR_SETPIXELV;
331     emr.emr.nSize  = sizeof(emr);
332     emr.ptlPixel.x = x;
333     emr.ptlPixel.y = y;
334     emr.crColor = color;
335
336     if (EMFDRV_WriteRecord( dev, &emr.emr )) {
337         RECTL bounds;
338         bounds.left = bounds.right = x;
339         bounds.top = bounds.bottom = y;
340         EMFDRV_UpdateBBox( dev, &bounds );
341         return color;
342     }
343     return -1;
344 }
345
346 /**********************************************************************
347  *          EMFDRV_Polylinegon
348  *
349  * Helper for EMFDRV_Poly{line|gon}
350  */
351 static BOOL
352 EMFDRV_Polylinegon( PHYSDEV dev, const POINT* pt, INT count, DWORD iType )
353 {
354     EMRPOLYLINE *emr;
355     DWORD size;
356     INT i;
357     BOOL ret;
358
359     size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
360
361     emr = HeapAlloc( GetProcessHeap(), 0, size );
362     emr->emr.iType = iType;
363     emr->emr.nSize = size;
364
365     emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
366     emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
367
368     for(i = 1; i < count; i++) {
369         if(pt[i].x < emr->rclBounds.left)
370             emr->rclBounds.left = pt[i].x;
371         else if(pt[i].x > emr->rclBounds.right)
372             emr->rclBounds.right = pt[i].x;
373         if(pt[i].y < emr->rclBounds.top)
374             emr->rclBounds.top = pt[i].y;
375         else if(pt[i].y > emr->rclBounds.bottom)
376             emr->rclBounds.bottom = pt[i].y;
377     }
378
379     emr->cptl = count;
380     memcpy(emr->aptl, pt, count * sizeof(POINTL));
381
382     ret = EMFDRV_WriteRecord( dev, &emr->emr );
383     if(ret)
384         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
385     HeapFree( GetProcessHeap(), 0, emr );
386     return ret;
387 }
388
389
390 /**********************************************************************
391  *          EMFDRV_Polylinegon16
392  *
393  * Helper for EMFDRV_Poly{line|gon}
394  *
395  *  This is not a legacy function!
396  *  We are using SHORT integers to save space.
397  */
398 static BOOL
399 EMFDRV_Polylinegon16( PHYSDEV dev, const POINT* pt, INT count, DWORD iType )
400 {
401     EMRPOLYLINE16 *emr;
402     DWORD size;
403     INT i;
404     BOOL ret;
405
406     /* check whether all points fit in the SHORT int POINT structure */
407     for(i = 0; i < count; i++) {
408         if( ((pt[i].x+0x8000) & ~0xffff ) || 
409             ((pt[i].y+0x8000) & ~0xffff ) )
410             return FALSE;
411     }
412
413     size = sizeof(EMRPOLYLINE16) + sizeof(POINTS) * (count - 1);
414
415     emr = HeapAlloc( GetProcessHeap(), 0, size );
416     emr->emr.iType = iType;
417     emr->emr.nSize = size;
418
419     emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
420     emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
421
422     for(i = 1; i < count; i++) {
423         if(pt[i].x < emr->rclBounds.left)
424             emr->rclBounds.left = pt[i].x;
425         else if(pt[i].x > emr->rclBounds.right)
426             emr->rclBounds.right = pt[i].x;
427         if(pt[i].y < emr->rclBounds.top)
428             emr->rclBounds.top = pt[i].y;
429         else if(pt[i].y > emr->rclBounds.bottom)
430             emr->rclBounds.bottom = pt[i].y;
431     }
432
433     emr->cpts = count;
434     for(i = 0; i < count; i++ ) {
435         emr->apts[i].x = pt[i].x;
436         emr->apts[i].y = pt[i].y;
437     }
438
439     ret = EMFDRV_WriteRecord( dev, &emr->emr );
440     if(ret)
441         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
442     HeapFree( GetProcessHeap(), 0, emr );
443     return ret;
444 }
445
446
447 /**********************************************************************
448  *          EMFDRV_Polyline
449  */
450 BOOL CDECL
451 EMFDRV_Polyline( PHYSDEV dev, const POINT* pt, INT count )
452 {
453     if( EMFDRV_Polylinegon16( dev, pt, count, EMR_POLYLINE16 ) )
454         return TRUE;
455     return EMFDRV_Polylinegon( dev, pt, count, EMR_POLYLINE );
456 }
457
458 /**********************************************************************
459  *          EMFDRV_Polygon
460  */
461 BOOL CDECL
462 EMFDRV_Polygon( PHYSDEV dev, const POINT* pt, INT count )
463 {
464     if(count < 2) return FALSE;
465     if( EMFDRV_Polylinegon16( dev, pt, count, EMR_POLYGON16 ) )
466         return TRUE;
467     return EMFDRV_Polylinegon( dev, pt, count, EMR_POLYGON );
468 }
469
470
471 /**********************************************************************
472  *          EMFDRV_PolyPolylinegon
473  *
474  * Helper for EMFDRV_PolyPoly{line|gon}
475  */
476 static BOOL
477 EMFDRV_PolyPolylinegon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT polys,
478                         DWORD iType)
479 {
480     EMRPOLYPOLYLINE *emr;
481     DWORD cptl = 0, poly, size;
482     INT point;
483     RECTL bounds;
484     const POINT *pts;
485     BOOL ret;
486
487     bounds.left = bounds.right = pt[0].x;
488     bounds.top = bounds.bottom = pt[0].y;
489
490     pts = pt;
491     for(poly = 0; poly < polys; poly++) {
492         cptl += counts[poly];
493         for(point = 0; point < counts[poly]; point++) {
494             if(bounds.left > pts->x) bounds.left = pts->x;
495             else if(bounds.right < pts->x) bounds.right = pts->x;
496             if(bounds.top > pts->y) bounds.top = pts->y;
497             else if(bounds.bottom < pts->y) bounds.bottom = pts->y;
498             pts++;
499         }
500     }
501
502     size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) +
503       (cptl - 1) * sizeof(POINTL);
504
505     emr = HeapAlloc( GetProcessHeap(), 0, size );
506
507     emr->emr.iType = iType;
508     emr->emr.nSize = size;
509     emr->rclBounds = bounds;
510     emr->nPolys = polys;
511     emr->cptl = cptl;
512     memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
513     memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
514     ret = EMFDRV_WriteRecord( dev, &emr->emr );
515     if(ret)
516         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
517     HeapFree( GetProcessHeap(), 0, emr );
518     return ret;
519 }
520
521 /**********************************************************************
522  *          EMFDRV_PolyPolyline
523  */
524 BOOL CDECL
525 EMFDRV_PolyPolyline(PHYSDEV dev, const POINT* pt, const DWORD* counts, DWORD polys)
526 {
527     return EMFDRV_PolyPolylinegon( dev, pt, (const INT *)counts, polys,
528                                    EMR_POLYPOLYLINE );
529 }
530
531 /**********************************************************************
532  *          EMFDRV_PolyPolygon
533  */
534 BOOL CDECL
535 EMFDRV_PolyPolygon( PHYSDEV dev, const POINT* pt, const INT* counts, UINT polys )
536 {
537     return EMFDRV_PolyPolylinegon( dev, pt, counts, polys, EMR_POLYPOLYGON );
538 }
539
540
541 /**********************************************************************
542  *          EMFDRV_ExtFloodFill
543  */
544 BOOL CDECL
545 EMFDRV_ExtFloodFill( PHYSDEV dev, INT x, INT y, COLORREF color, UINT fillType )
546 {
547     EMREXTFLOODFILL emr;
548
549     emr.emr.iType = EMR_EXTFLOODFILL;
550     emr.emr.nSize = sizeof(emr);
551     emr.ptlStart.x = x;
552     emr.ptlStart.y = y;
553     emr.crColor = color;
554     emr.iMode = fillType;
555
556     return EMFDRV_WriteRecord( dev, &emr.emr );
557 }
558
559
560 /*********************************************************************
561  *          EMFDRV_FillRgn
562  */
563 BOOL CDECL EMFDRV_FillRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush )
564 {
565     EMRFILLRGN *emr;
566     DWORD size, rgnsize, index;
567     BOOL ret;
568
569     index = EMFDRV_CreateBrushIndirect( dev, hbrush );
570     if(!index) return FALSE;
571
572     rgnsize = GetRegionData( hrgn, 0, NULL );
573     size = rgnsize + offsetof(EMRFILLRGN,RgnData);
574     emr = HeapAlloc( GetProcessHeap(), 0, size );
575
576     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
577
578     emr->emr.iType = EMR_FILLRGN;
579     emr->emr.nSize = size;
580     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
581     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
582     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
583     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
584     emr->cbRgnData = rgnsize;
585     emr->ihBrush = index;
586
587     ret = EMFDRV_WriteRecord( dev, &emr->emr );
588     if(ret)
589         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
590     HeapFree( GetProcessHeap(), 0, emr );
591     return ret;
592 }
593 /*********************************************************************
594  *          EMFDRV_FrameRgn
595  */
596 BOOL CDECL EMFDRV_FrameRgn( PHYSDEV dev, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
597 {
598     EMRFRAMERGN *emr;
599     DWORD size, rgnsize, index;
600     BOOL ret;
601
602     index = EMFDRV_CreateBrushIndirect( dev, hbrush );
603     if(!index) return FALSE;
604
605     rgnsize = GetRegionData( hrgn, 0, NULL );
606     size = rgnsize + offsetof(EMRFRAMERGN,RgnData);
607     emr = HeapAlloc( GetProcessHeap(), 0, size );
608
609     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
610
611     emr->emr.iType = EMR_FRAMERGN;
612     emr->emr.nSize = size;
613     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
614     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
615     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
616     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
617     emr->cbRgnData = rgnsize;
618     emr->ihBrush = index;
619     emr->szlStroke.cx = width;
620     emr->szlStroke.cy = height;
621
622     ret = EMFDRV_WriteRecord( dev, &emr->emr );
623     if(ret)
624         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
625     HeapFree( GetProcessHeap(), 0, emr );
626     return ret;
627 }
628
629 /*********************************************************************
630  *          EMFDRV_PaintInvertRgn
631  *
632  * Helper for EMFDRV_{Paint|Invert}Rgn
633  */
634 static BOOL EMFDRV_PaintInvertRgn( PHYSDEV dev, HRGN hrgn, DWORD iType )
635 {
636     EMRINVERTRGN *emr;
637     DWORD size, rgnsize;
638     BOOL ret;
639
640
641     rgnsize = GetRegionData( hrgn, 0, NULL );
642     size = rgnsize + offsetof(EMRINVERTRGN,RgnData);
643     emr = HeapAlloc( GetProcessHeap(), 0, size );
644
645     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
646
647     emr->emr.iType = iType;
648     emr->emr.nSize = size;
649     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
650     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
651     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
652     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
653     emr->cbRgnData = rgnsize;
654
655     ret = EMFDRV_WriteRecord( dev, &emr->emr );
656     if(ret)
657         EMFDRV_UpdateBBox( dev, &emr->rclBounds );
658     HeapFree( GetProcessHeap(), 0, emr );
659     return ret;
660 }
661
662 /**********************************************************************
663  *          EMFDRV_PaintRgn
664  */
665 BOOL CDECL
666 EMFDRV_PaintRgn( PHYSDEV dev, HRGN hrgn )
667 {
668     return EMFDRV_PaintInvertRgn( dev, hrgn, EMR_PAINTRGN );
669 }
670
671 /**********************************************************************
672  *          EMFDRV_InvertRgn
673  */
674 BOOL CDECL
675 EMFDRV_InvertRgn( PHYSDEV dev, HRGN hrgn )
676 {
677     return EMFDRV_PaintInvertRgn( dev, hrgn, EMR_INVERTRGN );
678 }
679
680 /**********************************************************************
681  *          EMFDRV_SetBkColor
682  */
683 COLORREF CDECL
684 EMFDRV_SetBkColor( PHYSDEV dev, COLORREF color )
685 {
686     EMRSETBKCOLOR emr;
687     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
688
689     if (physDev->restoring) return color;  /* don't output records during RestoreDC */
690
691     emr.emr.iType = EMR_SETBKCOLOR;
692     emr.emr.nSize = sizeof(emr);
693     emr.crColor = color;
694
695     return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID;
696 }
697
698
699 /**********************************************************************
700  *          EMFDRV_SetTextColor
701  */
702 COLORREF CDECL
703 EMFDRV_SetTextColor( PHYSDEV dev, COLORREF color )
704 {
705     EMRSETTEXTCOLOR emr;
706     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE *)dev;
707
708     if (physDev->restoring) return color;  /* don't output records during RestoreDC */
709
710     emr.emr.iType = EMR_SETTEXTCOLOR;
711     emr.emr.nSize = sizeof(emr);
712     emr.crColor = color;
713
714     return EMFDRV_WriteRecord( dev, &emr.emr ) ? color : CLR_INVALID;
715 }
716
717 /**********************************************************************
718  *          EMFDRV_ExtTextOut
719  */
720 BOOL CDECL EMFDRV_ExtTextOut( PHYSDEV dev, INT x, INT y, UINT flags,
721                               const RECT *lprect, LPCWSTR str, UINT count,
722                               const INT *lpDx )
723 {
724     EMREXTTEXTOUTW *pemr;
725     DWORD nSize;
726     BOOL ret;
727     EMFDRV_PDEVICE *physDev = (EMFDRV_PDEVICE*) dev;
728     int textHeight = 0;
729     int textWidth = 0;
730     const UINT textAlign = GetTextAlign(physDev->hdc);
731
732     nSize = sizeof(*pemr) + ((count+1) & ~1) * sizeof(WCHAR) + count * sizeof(INT);
733
734     TRACE("%s %s count %d nSize = %d\n", debugstr_wn(str, count),
735            wine_dbgstr_rect(lprect), count, nSize);
736     pemr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSize);
737
738     pemr->emr.iType = EMR_EXTTEXTOUTW;
739     pemr->emr.nSize = nSize;
740
741     pemr->iGraphicsMode = GetGraphicsMode(physDev->hdc);
742     pemr->exScale = pemr->eyScale = 1.0; /* FIXME */
743
744     pemr->emrtext.ptlReference.x = x;
745     pemr->emrtext.ptlReference.y = y;
746     pemr->emrtext.nChars = count;
747     pemr->emrtext.offString = sizeof(*pemr);
748     memcpy((char*)pemr + pemr->emrtext.offString, str, count * sizeof(WCHAR));
749     pemr->emrtext.fOptions = flags;
750     if(!lprect) {
751         pemr->emrtext.rcl.left = pemr->emrtext.rcl.top = 0;
752         pemr->emrtext.rcl.right = pemr->emrtext.rcl.bottom = -1;
753     } else {
754         pemr->emrtext.rcl.left = lprect->left;
755         pemr->emrtext.rcl.top = lprect->top;
756         pemr->emrtext.rcl.right = lprect->right;
757         pemr->emrtext.rcl.bottom = lprect->bottom;
758     }
759
760     pemr->emrtext.offDx = pemr->emrtext.offString + ((count+1) & ~1) * sizeof(WCHAR);
761     if(lpDx) {
762         UINT i;
763         SIZE strSize;
764         memcpy((char*)pemr + pemr->emrtext.offDx, lpDx, count * sizeof(INT));
765         for (i = 0; i < count; i++) {
766             textWidth += lpDx[i];
767         }
768         if (GetTextExtentPoint32W(physDev->hdc, str, count, &strSize))
769             textHeight = strSize.cy;
770     }
771     else {
772         UINT i;
773         INT *dx = (INT *)((char*)pemr + pemr->emrtext.offDx);
774         SIZE charSize;
775         for (i = 0; i < count; i++) {
776             if (GetTextExtentPoint32W(physDev->hdc, str + i, 1, &charSize)) {
777                 dx[i] = charSize.cx;
778                 textWidth += charSize.cx;
779                 textHeight = max(textHeight, charSize.cy);
780             }
781         }
782     }
783
784     if (!lprect)
785     {
786         pemr->rclBounds.left = pemr->rclBounds.top = 0;
787         pemr->rclBounds.right = pemr->rclBounds.bottom = -1;
788         goto no_bounds;
789     }
790
791     switch (textAlign & (TA_LEFT | TA_RIGHT | TA_CENTER)) {
792     case TA_CENTER: {
793         pemr->rclBounds.left  = x - (textWidth / 2) - 1;
794         pemr->rclBounds.right = x + (textWidth / 2) + 1;
795         break;
796     }
797     case TA_RIGHT: {
798         pemr->rclBounds.left  = x - textWidth - 1;
799         pemr->rclBounds.right = x;
800         break;
801     }
802     default: { /* TA_LEFT */
803         pemr->rclBounds.left  = x;
804         pemr->rclBounds.right = x + textWidth + 1;
805     }
806     }
807
808     switch (textAlign & (TA_TOP | TA_BOTTOM | TA_BASELINE)) {
809     case TA_BASELINE: {
810         TEXTMETRICW tm;
811         if (!GetTextMetricsW(physDev->hdc, &tm))
812             tm.tmDescent = 0;
813         /* Play safe here... it's better to have a bounding box */
814         /* that is too big than too small. */
815         pemr->rclBounds.top    = y - textHeight - 1;
816         pemr->rclBounds.bottom = y + tm.tmDescent + 1;
817         break;
818     }
819     case TA_BOTTOM: {
820         pemr->rclBounds.top    = y - textHeight - 1;
821         pemr->rclBounds.bottom = y;
822         break;
823     }
824     default: { /* TA_TOP */
825         pemr->rclBounds.top    = y;
826         pemr->rclBounds.bottom = y + textHeight + 1;
827     }
828     }
829     EMFDRV_UpdateBBox( dev, &pemr->rclBounds );
830
831 no_bounds:
832     ret = EMFDRV_WriteRecord( dev, &pemr->emr );
833     HeapFree( GetProcessHeap(), 0, pemr );
834     return ret;
835 }
836
837 /**********************************************************************
838  *          EMFDRV_SetArcDirection
839  */
840 INT CDECL EMFDRV_SetArcDirection(PHYSDEV dev, INT arcDirection)
841 {
842     EMRSETARCDIRECTION emr;
843
844     emr.emr.iType = EMR_SETARCDIRECTION;
845     emr.emr.nSize = sizeof(emr);
846     emr.iArcDirection = arcDirection;
847
848     EMFDRV_WriteRecord(dev, &emr.emr);
849
850     /* We don't know the old arc direction and we don't care... */ 
851     return 0;
852 }