Check the value returned by DIALOG_GetCharSize.
[wine] / graphics / enhmetafiledrv / graphics.c
1 /*
2  * Enhanced MetaFile driver graphics functions
3  *
4  * Copyright 1999 Huw D M Davies
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "gdi.h"
11 #include "dc.h"
12 #include "enhmetafiledrv.h"
13 #include "heap.h"
14 #include "debugtools.h"
15
16 DEFAULT_DEBUG_CHANNEL(enhmetafile)
17
18 /**********************************************************************
19  *           EMFDRV_MoveToEx
20  */
21 BOOL
22 EMFDRV_MoveToEx(DC *dc,INT x,INT y,LPPOINT pt)
23 {
24     EMRMOVETOEX emr;
25
26     emr.emr.iType = EMR_MOVETOEX;
27     emr.emr.nSize = sizeof(emr);
28     emr.ptl.x = x;
29     emr.ptl.y = y;
30
31     return EMFDRV_WriteRecord( dc, &emr.emr );
32 }
33
34 /***********************************************************************
35  *           EMFDRV_LineTo
36  */
37 BOOL
38 EMFDRV_LineTo( DC *dc, INT x, INT y )
39 {
40     EMRLINETO emr;
41     RECTL bounds;
42
43     emr.emr.iType = EMR_LINETO;
44     emr.emr.nSize = sizeof(emr);
45     emr.ptl.x = x;
46     emr.ptl.y = y;
47
48     if(!EMFDRV_WriteRecord( dc, &emr.emr ))
49         return FALSE;
50
51     bounds.left   = min(x, dc->w.CursPosX);
52     bounds.top    = min(y, dc->w.CursPosY);
53     bounds.right  = max(x, dc->w.CursPosX);
54     bounds.bottom = max(y, dc->w.CursPosY);
55
56     EMFDRV_UpdateBBox( dc, &bounds );
57
58     return TRUE;
59 }
60
61
62 /***********************************************************************
63  *           EMFDRV_ArcChordPie
64  */
65 static BOOL
66 EMFDRV_ArcChordPie( DC *dc, INT left, INT top, INT right, INT bottom,
67                     INT xstart, INT ystart, INT xend, INT yend, DWORD iType )
68 {
69     INT temp, xCentre, yCentre, i;
70     double angleStart, angleEnd;
71     double xinterStart, yinterStart, xinterEnd, yinterEnd;
72     EMRARC emr;
73     RECTL bounds;
74
75     if(left == right || top == bottom) return FALSE;
76
77     if(left > right) {temp = left; left = right; right = temp;}
78     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
79
80     if(dc->w.GraphicsMode == GM_COMPATIBLE) {
81         right--;
82         bottom--;
83     }
84
85     emr.emr.iType     = iType;
86     emr.emr.nSize     = sizeof(emr);
87     emr.rclBox.left   = left;
88     emr.rclBox.top    = top;
89     emr.rclBox.right  = right;
90     emr.rclBox.bottom = bottom;
91     emr.ptlStart.x    = xstart;
92     emr.ptlStart.y    = ystart;
93     emr.ptlEnd.x      = xend;
94     emr.ptlEnd.x      = yend;
95
96
97     /* Now calculate the BBox */
98     xCentre = (left + right + 1) / 2;
99     yCentre = (top + bottom + 1) / 2;
100
101     xstart -= xCentre;
102     ystart -= yCentre;
103     xend   -= xCentre;
104     yend   -= yCentre;
105
106     /* invert y co-ords to get angle anti-clockwise from x-axis */
107     angleStart = atan2( -(double)ystart, (double)xstart);
108     angleEnd   = atan2( -(double)yend, (double)xend);
109
110     /* These are the intercepts of the start/end lines with the arc */
111
112     xinterStart = (right - left + 1)/2 * cos(angleStart) + xCentre;
113     yinterStart = -(bottom - top + 1)/2 * sin(angleStart) + yCentre;
114     xinterEnd   = (right - left + 1)/2 * cos(angleEnd) + xCentre;
115     yinterEnd   = -(bottom - top + 1)/2 * sin(angleEnd) + yCentre;
116
117     if(angleStart < 0) angleStart += 2 * M_PI;
118     if(angleEnd < 0) angleEnd += 2 * M_PI;
119     if(angleEnd < angleStart) angleEnd += 2 * M_PI;
120
121     bounds.left   = min(xinterStart, xinterEnd);
122     bounds.top    = min(yinterStart, yinterEnd);
123     bounds.right  = max(xinterStart, xinterEnd);
124     bounds.bottom = max(yinterStart, yinterEnd);
125     
126     for(i = 0; i <= 8; i++) {
127         if(i * M_PI / 2 < angleStart) /* loop until we're past start */
128             continue;
129         if(i * M_PI / 2 > angleEnd)   /* if we're past end we're finished */
130             break;
131
132         /* the arc touches the rectangle at the start of quadrant i, so adjust
133            BBox to reflect this. */
134
135         switch(i % 4) { 
136         case 0:
137             bounds.right = right;
138             break;
139         case 1:
140             bounds.top = top;
141             break;
142         case 2:
143             bounds.left = left;
144             break;
145         case 3:
146             bounds.bottom = bottom;
147             break;
148         }
149     }
150
151     /* If we're drawing a pie then make sure we include the centre */
152     if(iType == EMR_PIE) {
153         if(bounds.left > xCentre) bounds.left = xCentre;
154         else if(bounds.right < xCentre) bounds.right = xCentre;
155         if(bounds.top > yCentre) bounds.top = yCentre;
156         else if(bounds.bottom < yCentre) bounds.right = yCentre;
157     }
158     if(!EMFDRV_WriteRecord( dc, &emr.emr ))
159         return FALSE;
160     EMFDRV_UpdateBBox( dc, &bounds );
161     return TRUE;
162 }
163
164
165 /***********************************************************************
166  *           EMFDRV_Arc
167  */
168 BOOL
169 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
170             INT xstart, INT ystart, INT xend, INT yend )
171 {
172     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
173                                xend, yend, EMR_ARC );
174 }
175
176 /***********************************************************************
177  *           EMFDRV_Pie
178  */
179 BOOL
180 EMFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
181             INT xstart, INT ystart, INT xend, INT yend )
182 {
183     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
184                                xend, yend, EMR_PIE );
185 }
186
187
188 /***********************************************************************
189  *           EMFDRV_Chord
190  */
191 BOOL
192 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
193              INT xstart, INT ystart, INT xend, INT yend )
194 {
195     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
196                                xend, yend, EMR_CHORD );
197 }
198
199 /***********************************************************************
200  *           EMFDRV_Ellipse
201  */
202 BOOL
203 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
204 {
205     EMRELLIPSE emr;
206     INT temp;
207
208     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
209
210     if(left == right || top == bottom) return FALSE;
211
212     if(left > right) {temp = left; left = right; right = temp;}
213     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
214
215     if(dc->w.GraphicsMode == GM_COMPATIBLE) {
216         right--;
217         bottom--;
218     }
219
220     emr.emr.iType     = EMR_ELLIPSE;
221     emr.emr.nSize     = sizeof(emr);
222     emr.rclBox.left   = left;
223     emr.rclBox.top    = top;
224     emr.rclBox.right  = right;
225     emr.rclBox.bottom = bottom;
226
227     EMFDRV_UpdateBBox( dc, &emr.rclBox );
228     return EMFDRV_WriteRecord( dc, &emr.emr );
229 }
230
231 /***********************************************************************
232  *           EMFDRV_Rectangle
233  */
234 BOOL
235 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
236 {
237     EMRRECTANGLE emr;
238     INT temp;
239
240     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
241
242     if(left == right || top == bottom) return FALSE;
243
244     if(left > right) {temp = left; left = right; right = temp;}
245     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
246
247     if(dc->w.GraphicsMode == GM_COMPATIBLE) {
248         right--;
249         bottom--;
250     }
251
252     emr.emr.iType     = EMR_RECTANGLE;
253     emr.emr.nSize     = sizeof(emr);
254     emr.rclBox.left   = left;
255     emr.rclBox.top    = top;
256     emr.rclBox.right  = right;
257     emr.rclBox.bottom = bottom;
258
259     EMFDRV_UpdateBBox( dc, &emr.rclBox );
260     return EMFDRV_WriteRecord( dc, &emr.emr );
261 }
262
263 /***********************************************************************
264  *           EMFDRV_RoundRect
265  */
266 BOOL 
267 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
268                   INT bottom, INT ell_width, INT ell_height )
269 {
270     EMRROUNDRECT emr;
271     INT temp;
272
273     if(left == right || top == bottom) return FALSE;
274
275     if(left > right) {temp = left; left = right; right = temp;}
276     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
277
278     if(dc->w.GraphicsMode == GM_COMPATIBLE) {
279         right--;
280         bottom--;
281     }
282
283     emr.emr.iType     = EMR_ROUNDRECT;
284     emr.emr.nSize     = sizeof(emr);
285     emr.rclBox.left   = left;
286     emr.rclBox.top    = top;
287     emr.rclBox.right  = right;
288     emr.rclBox.bottom = bottom;
289     emr.szlCorner.cx  = ell_width;
290     emr.szlCorner.cy  = ell_height;
291
292     EMFDRV_UpdateBBox( dc, &emr.rclBox );
293     return EMFDRV_WriteRecord( dc, &emr.emr );
294 }
295
296 /***********************************************************************
297  *           EMFDRV_SetPixel
298  */
299 COLORREF
300 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
301 {
302   return TRUE;
303 }
304
305
306 /**********************************************************************
307  *          EMFDRV_Polylinegon
308  *
309  * Helper for EMFDRV_Poly{line|gon}
310  */
311 static BOOL
312 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
313 {
314     EMRPOLYLINE *emr;
315     DWORD size;
316     INT i;
317     BOOL ret;
318
319     size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
320
321     emr = HeapAlloc( GetProcessHeap(), 0, size );
322     emr->emr.iType = iType;
323     emr->emr.nSize = size;
324     
325     emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
326     emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
327
328     for(i = 1; i < count; i++) {
329         if(pt[i].x < emr->rclBounds.left)
330             emr->rclBounds.left = pt[i].x;
331         else if(pt[i].x > emr->rclBounds.right)
332             emr->rclBounds.right = pt[i].x;
333         if(pt[i].y < emr->rclBounds.top)
334             emr->rclBounds.top = pt[i].y;
335         else if(pt[i].y > emr->rclBounds.bottom)
336             emr->rclBounds.bottom = pt[i].y;
337     }
338
339     emr->cptl = count;
340     memcpy(emr->aptl, pt, count * sizeof(POINTL));
341
342     ret = EMFDRV_WriteRecord( dc, &emr->emr );
343     if(ret)
344         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
345     HeapFree( GetProcessHeap(), 0, emr );
346     return ret;
347 }
348
349
350 /**********************************************************************
351  *          EMFDRV_Polyline
352  */
353 BOOL
354 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
355 {
356     return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
357 }
358
359 /**********************************************************************
360  *          EMFDRV_Polygon
361  */
362 BOOL
363 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
364 {
365     if(count < 2) return FALSE;
366     return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
367 }
368
369
370 /**********************************************************************
371  *          EMFDRV_PolyPolylinegon
372  *
373  * Helper for EMFDRV_PolyPoly{line|gon}
374  */
375 static BOOL 
376 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
377                         DWORD iType)
378 {
379     EMRPOLYPOLYLINE *emr;
380     DWORD cptl = 0, poly, size, point;
381     RECTL bounds;
382     const POINT *pts;
383     BOOL ret;
384
385     bounds.left = bounds.right = pt[0].x;
386     bounds.top = bounds.bottom = pt[0].y;
387
388     pts = pt;
389     for(poly = 0; poly < polys; poly++) {
390         cptl += counts[poly];
391         for(point = 0; point < counts[poly]; point++) {
392             if(bounds.left > pts->x) bounds.left = pts->x;
393             else if(bounds.right < pts->x) bounds.right = pts->x;
394             if(bounds.top > pts->y) bounds.top = pts->y;
395             else if(bounds.bottom < pts->y) bounds.bottom = pts->y;
396             pts++;
397         }
398     }
399     
400     size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) + 
401       (cptl - 1) * sizeof(POINTL);
402
403     emr = HeapAlloc( GetProcessHeap(), 0, size );
404
405     emr->emr.iType = iType;
406     emr->emr.nSize = size;
407     emr->rclBounds = bounds;
408     emr->nPolys = polys;
409     emr->cptl = cptl;
410     memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
411     memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
412     ret = EMFDRV_WriteRecord( dc, &emr->emr );
413     if(ret)
414         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
415     HeapFree( GetProcessHeap(), 0, emr );
416     return ret;
417 }
418
419 /**********************************************************************
420  *          EMFDRV_PolyPolyline
421  */
422 BOOL 
423 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
424 {
425     return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
426                                    EMR_POLYPOLYLINE );
427 }
428
429 /**********************************************************************
430  *          EMFDRV_PolyPolygon
431  */
432 BOOL 
433 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
434 {
435     return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
436 }
437
438
439 /**********************************************************************
440  *          EMFDRV_ExtFloodFill
441  */
442 BOOL 
443 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
444 {
445     EMREXTFLOODFILL emr;
446
447     emr.emr.iType = EMR_EXTFLOODFILL;
448     emr.emr.nSize = sizeof(emr);
449     emr.ptlStart.x = x;
450     emr.ptlStart.y = y;
451     emr.crColor = color;
452     emr.iMode = fillType;
453
454     return EMFDRV_WriteRecord( dc, &emr.emr );
455 }
456
457
458 /*********************************************************************
459  *          EMFDRV_FillRgn
460  */
461 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
462 {
463     EMRFILLRGN *emr;
464     DWORD size, rgnsize, index;
465     BOOL ret;
466
467     index = EMFDRV_CreateBrushIndirect( dc, hbrush );
468     if(!index) return FALSE;
469
470     rgnsize = GetRegionData( hrgn, 0, NULL );
471     size = rgnsize + sizeof(EMRFILLRGN) - 1;
472     emr = HeapAlloc( GetProcessHeap(), 0, size );
473
474     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
475
476     emr->emr.iType = EMR_FILLRGN;
477     emr->emr.nSize = size;
478     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
479     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
480     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
481     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
482     emr->cbRgnData = rgnsize;
483     emr->ihBrush = index;
484     
485     ret = EMFDRV_WriteRecord( dc, &emr->emr );
486     if(ret)
487         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
488     HeapFree( GetProcessHeap(), 0, emr );
489     return ret;
490 }
491 /*********************************************************************
492  *          EMFDRV_FrameRgn
493  */
494 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
495 {
496     EMRFRAMERGN *emr;
497     DWORD size, rgnsize, index;
498     BOOL ret;
499
500     index = EMFDRV_CreateBrushIndirect( dc, hbrush );
501     if(!index) return FALSE;
502
503     rgnsize = GetRegionData( hrgn, 0, NULL );
504     size = rgnsize + sizeof(EMRFRAMERGN) - 1;
505     emr = HeapAlloc( GetProcessHeap(), 0, size );
506
507     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
508
509     emr->emr.iType = EMR_FRAMERGN;
510     emr->emr.nSize = size;
511     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
512     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
513     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
514     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
515     emr->cbRgnData = rgnsize;
516     emr->ihBrush = index;
517     emr->szlStroke.cx = width;
518     emr->szlStroke.cy = height;
519
520     ret = EMFDRV_WriteRecord( dc, &emr->emr );
521     if(ret)
522         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
523     HeapFree( GetProcessHeap(), 0, emr );
524     return ret;
525 }
526
527 /*********************************************************************
528  *          EMFDRV_PaintInvertRgn
529  *
530  * Helper for EMFDRV_{Paint|Invert}Rgn
531  */
532 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
533 {
534     EMRINVERTRGN *emr;
535     DWORD size, rgnsize;
536     BOOL ret;
537
538
539     rgnsize = GetRegionData( hrgn, 0, NULL );
540     size = rgnsize + sizeof(EMRINVERTRGN) - 1;
541     emr = HeapAlloc( GetProcessHeap(), 0, size );
542
543     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
544
545     emr->emr.iType = iType;
546     emr->emr.nSize = size;
547     emr->rclBounds.left   = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
548     emr->rclBounds.top    = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
549     emr->rclBounds.right  = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
550     emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
551     emr->cbRgnData = rgnsize;
552     
553     ret = EMFDRV_WriteRecord( dc, &emr->emr );
554     if(ret)
555         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
556     HeapFree( GetProcessHeap(), 0, emr );
557     return ret;
558 }
559
560 /**********************************************************************
561  *          EMFDRV_PaintRgn
562  */
563 BOOL
564 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
565 {
566     return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
567 }
568
569 /**********************************************************************
570  *          EMFDRV_InvertRgn
571  */
572 BOOL
573 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
574 {
575     return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
576 }
577
578 /**********************************************************************
579  *          EMFDRV_SetBkColor
580  */
581 COLORREF
582 EMFDRV_SetBkColor( DC *dc, COLORREF color )
583 {
584     EMRSETBKCOLOR emr;
585
586     emr.emr.iType = EMR_SETBKCOLOR;
587     emr.emr.nSize = sizeof(emr);
588     emr.crColor = color;
589
590     return EMFDRV_WriteRecord( dc, &emr.emr );
591 }
592
593
594 /**********************************************************************
595  *          EMFDRV_SetTextColor
596  */
597 COLORREF
598 EMFDRV_SetTextColor( DC *dc, COLORREF color )
599 {
600     EMRSETTEXTCOLOR emr;
601
602     emr.emr.iType = EMR_SETTEXTCOLOR;
603     emr.emr.nSize = sizeof(emr);
604     emr.crColor = color;
605
606     return EMFDRV_WriteRecord( dc, &emr.emr );
607 }