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