2 * Enhanced MetaFile driver graphics functions
4 * Copyright 1999 Huw D M Davies
12 #include "enhmetafiledrv.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(enhmetafile
)
18 /**********************************************************************
22 EMFDRV_MoveToEx(DC
*dc
,INT x
,INT y
,LPPOINT pt
)
26 emr
.emr
.iType
= EMR_MOVETOEX
;
27 emr
.emr
.nSize
= sizeof(emr
);
31 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
34 /***********************************************************************
38 EMFDRV_LineTo( DC
*dc
, INT x
, INT y
)
43 emr
.emr
.iType
= EMR_LINETO
;
44 emr
.emr
.nSize
= sizeof(emr
);
48 if(!EMFDRV_WriteRecord( dc
, &emr
.emr
))
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
);
56 EMFDRV_UpdateBBox( dc
, &bounds
);
62 /***********************************************************************
66 EMFDRV_ArcChordPie( DC
*dc
, INT left
, INT top
, INT right
, INT bottom
,
67 INT xstart
, INT ystart
, INT xend
, INT yend
, DWORD iType
)
69 INT temp
, xCentre
, yCentre
, i
;
70 double angleStart
, angleEnd
;
71 double xinterStart
, yinterStart
, xinterEnd
, yinterEnd
;
75 if(left
== right
|| top
== bottom
) return FALSE
;
77 if(left
> right
) {temp
= left
; left
= right
; right
= temp
;}
78 if(top
> bottom
) {temp
= top
; top
= bottom
; bottom
= temp
;}
80 if(dc
->w
.GraphicsMode
== GM_COMPATIBLE
) {
85 emr
.emr
.iType
= iType
;
86 emr
.emr
.nSize
= sizeof(emr
);
87 emr
.rclBox
.left
= left
;
89 emr
.rclBox
.right
= right
;
90 emr
.rclBox
.bottom
= bottom
;
91 emr
.ptlStart
.x
= xstart
;
92 emr
.ptlStart
.y
= ystart
;
97 /* Now calculate the BBox */
98 xCentre
= (left
+ right
+ 1) / 2;
99 yCentre
= (top
+ bottom
+ 1) / 2;
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
);
110 /* These are the intercepts of the start/end lines with the arc */
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
;
117 if(angleStart
< 0) angleStart
+= 2 * M_PI
;
118 if(angleEnd
< 0) angleEnd
+= 2 * M_PI
;
119 if(angleEnd
< angleStart
) angleEnd
+= 2 * M_PI
;
121 bounds
.left
= min(xinterStart
, xinterEnd
);
122 bounds
.top
= min(yinterStart
, yinterEnd
);
123 bounds
.right
= max(xinterStart
, xinterEnd
);
124 bounds
.bottom
= max(yinterStart
, yinterEnd
);
126 for(i
= 0; i
<= 8; i
++) {
127 if(i
* M_PI
/ 2 < angleStart
) /* loop until we're past start */
129 if(i
* M_PI
/ 2 > angleEnd
) /* if we're past end we're finished */
132 /* the arc touches the rectangle at the start of quadrant i, so adjust
133 BBox to reflect this. */
137 bounds
.right
= right
;
146 bounds
.bottom
= bottom
;
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
;
158 if(!EMFDRV_WriteRecord( dc
, &emr
.emr
))
160 EMFDRV_UpdateBBox( dc
, &bounds
);
165 /***********************************************************************
169 EMFDRV_Arc( DC
*dc
, INT left
, INT top
, INT right
, INT bottom
,
170 INT xstart
, INT ystart
, INT xend
, INT yend
)
172 return EMFDRV_ArcChordPie( dc
, left
, top
, right
, bottom
, xstart
, ystart
,
173 xend
, yend
, EMR_ARC
);
176 /***********************************************************************
180 EMFDRV_Pie( DC
*dc
, INT left
, INT top
, INT right
, INT bottom
,
181 INT xstart
, INT ystart
, INT xend
, INT yend
)
183 return EMFDRV_ArcChordPie( dc
, left
, top
, right
, bottom
, xstart
, ystart
,
184 xend
, yend
, EMR_PIE
);
188 /***********************************************************************
192 EMFDRV_Chord( DC
*dc
, INT left
, INT top
, INT right
, INT bottom
,
193 INT xstart
, INT ystart
, INT xend
, INT yend
)
195 return EMFDRV_ArcChordPie( dc
, left
, top
, right
, bottom
, xstart
, ystart
,
196 xend
, yend
, EMR_CHORD
);
199 /***********************************************************************
203 EMFDRV_Ellipse( DC
*dc
, INT left
, INT top
, INT right
, INT bottom
)
208 TRACE("%d,%d - %d,%d\n", left
, top
, right
, bottom
);
210 if(left
== right
|| top
== bottom
) return FALSE
;
212 if(left
> right
) {temp
= left
; left
= right
; right
= temp
;}
213 if(top
> bottom
) {temp
= top
; top
= bottom
; bottom
= temp
;}
215 if(dc
->w
.GraphicsMode
== GM_COMPATIBLE
) {
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
;
227 EMFDRV_UpdateBBox( dc
, &emr
.rclBox
);
228 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
231 /***********************************************************************
235 EMFDRV_Rectangle(DC
*dc
, INT left
, INT top
, INT right
, INT bottom
)
240 TRACE("%d,%d - %d,%d\n", left
, top
, right
, bottom
);
242 if(left
== right
|| top
== bottom
) return FALSE
;
244 if(left
> right
) {temp
= left
; left
= right
; right
= temp
;}
245 if(top
> bottom
) {temp
= top
; top
= bottom
; bottom
= temp
;}
247 if(dc
->w
.GraphicsMode
== GM_COMPATIBLE
) {
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
;
259 EMFDRV_UpdateBBox( dc
, &emr
.rclBox
);
260 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
263 /***********************************************************************
267 EMFDRV_RoundRect( DC
*dc
, INT left
, INT top
, INT right
,
268 INT bottom
, INT ell_width
, INT ell_height
)
273 if(left
== right
|| top
== bottom
) return FALSE
;
275 if(left
> right
) {temp
= left
; left
= right
; right
= temp
;}
276 if(top
> bottom
) {temp
= top
; top
= bottom
; bottom
= temp
;}
278 if(dc
->w
.GraphicsMode
== GM_COMPATIBLE
) {
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
;
292 EMFDRV_UpdateBBox( dc
, &emr
.rclBox
);
293 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
296 /***********************************************************************
300 EMFDRV_SetPixel( DC
*dc
, INT x
, INT y
, COLORREF color
)
306 /**********************************************************************
309 * Helper for EMFDRV_Poly{line|gon}
312 EMFDRV_Polylinegon( DC
*dc
, const POINT
* pt
, INT count
, DWORD iType
)
319 size
= sizeof(EMRPOLYLINE
) + sizeof(POINTL
) * (count
- 1);
321 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
322 emr
->emr
.iType
= iType
;
323 emr
->emr
.nSize
= size
;
325 emr
->rclBounds
.left
= emr
->rclBounds
.right
= pt
[0].x
;
326 emr
->rclBounds
.top
= emr
->rclBounds
.bottom
= pt
[0].y
;
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
;
340 memcpy(emr
->aptl
, pt
, count
* sizeof(POINTL
));
342 ret
= EMFDRV_WriteRecord( dc
, &emr
->emr
);
344 EMFDRV_UpdateBBox( dc
, &emr
->rclBounds
);
345 HeapFree( GetProcessHeap(), 0, emr
);
350 /**********************************************************************
354 EMFDRV_Polyline( DC
*dc
, const POINT
* pt
, INT count
)
356 return EMFDRV_Polylinegon( dc
, pt
, count
, EMR_POLYLINE
);
359 /**********************************************************************
363 EMFDRV_Polygon( DC
*dc
, const POINT
* pt
, INT count
)
365 if(count
< 2) return FALSE
;
366 return EMFDRV_Polylinegon( dc
, pt
, count
, EMR_POLYGON
);
370 /**********************************************************************
371 * EMFDRV_PolyPolylinegon
373 * Helper for EMFDRV_PolyPoly{line|gon}
376 EMFDRV_PolyPolylinegon( DC
*dc
, const POINT
* pt
, const INT
* counts
, UINT polys
,
379 EMRPOLYPOLYLINE
*emr
;
380 DWORD cptl
= 0, poly
, size
, point
;
385 bounds
.left
= bounds
.right
= pt
[0].x
;
386 bounds
.top
= bounds
.bottom
= pt
[0].y
;
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
;
400 size
= sizeof(EMRPOLYPOLYLINE
) + (polys
- 1) * sizeof(DWORD
) +
401 (cptl
- 1) * sizeof(POINTL
);
403 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
405 emr
->emr
.iType
= iType
;
406 emr
->emr
.nSize
= size
;
407 emr
->rclBounds
= bounds
;
410 memcpy(emr
->aPolyCounts
, counts
, polys
* sizeof(DWORD
));
411 memcpy(emr
->aPolyCounts
+ polys
, pt
, cptl
* sizeof(POINTL
));
412 ret
= EMFDRV_WriteRecord( dc
, &emr
->emr
);
414 EMFDRV_UpdateBBox( dc
, &emr
->rclBounds
);
415 HeapFree( GetProcessHeap(), 0, emr
);
419 /**********************************************************************
420 * EMFDRV_PolyPolyline
423 EMFDRV_PolyPolyline(DC
*dc
, const POINT
* pt
, const DWORD
* counts
, DWORD polys
)
425 return EMFDRV_PolyPolylinegon( dc
, pt
, (INT
*)counts
, polys
,
429 /**********************************************************************
433 EMFDRV_PolyPolygon( DC
*dc
, const POINT
* pt
, const INT
* counts
, UINT polys
)
435 return EMFDRV_PolyPolylinegon( dc
, pt
, counts
, polys
, EMR_POLYPOLYGON
);
439 /**********************************************************************
440 * EMFDRV_ExtFloodFill
443 EMFDRV_ExtFloodFill( DC
*dc
, INT x
, INT y
, COLORREF color
, UINT fillType
)
447 emr
.emr
.iType
= EMR_EXTFLOODFILL
;
448 emr
.emr
.nSize
= sizeof(emr
);
452 emr
.iMode
= fillType
;
454 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
458 /*********************************************************************
461 BOOL
EMFDRV_FillRgn( DC
*dc
, HRGN hrgn
, HBRUSH hbrush
)
464 DWORD size
, rgnsize
, index
;
467 index
= EMFDRV_CreateBrushIndirect( dc
, hbrush
);
468 if(!index
) return FALSE
;
470 rgnsize
= GetRegionData( hrgn
, 0, NULL
);
471 size
= rgnsize
+ sizeof(EMRFILLRGN
) - 1;
472 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
474 GetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
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
;
485 ret
= EMFDRV_WriteRecord( dc
, &emr
->emr
);
487 EMFDRV_UpdateBBox( dc
, &emr
->rclBounds
);
488 HeapFree( GetProcessHeap(), 0, emr
);
491 /*********************************************************************
494 BOOL
EMFDRV_FrameRgn( DC
*dc
, HRGN hrgn
, HBRUSH hbrush
, INT width
, INT height
)
497 DWORD size
, rgnsize
, index
;
500 index
= EMFDRV_CreateBrushIndirect( dc
, hbrush
);
501 if(!index
) return FALSE
;
503 rgnsize
= GetRegionData( hrgn
, 0, NULL
);
504 size
= rgnsize
+ sizeof(EMRFRAMERGN
) - 1;
505 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
507 GetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
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
;
520 ret
= EMFDRV_WriteRecord( dc
, &emr
->emr
);
522 EMFDRV_UpdateBBox( dc
, &emr
->rclBounds
);
523 HeapFree( GetProcessHeap(), 0, emr
);
527 /*********************************************************************
528 * EMFDRV_PaintInvertRgn
530 * Helper for EMFDRV_{Paint|Invert}Rgn
532 static BOOL
EMFDRV_PaintInvertRgn( DC
*dc
, HRGN hrgn
, DWORD iType
)
539 rgnsize
= GetRegionData( hrgn
, 0, NULL
);
540 size
= rgnsize
+ sizeof(EMRINVERTRGN
) - 1;
541 emr
= HeapAlloc( GetProcessHeap(), 0, size
);
543 GetRegionData( hrgn
, rgnsize
, (RGNDATA
*)&emr
->RgnData
);
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
;
553 ret
= EMFDRV_WriteRecord( dc
, &emr
->emr
);
555 EMFDRV_UpdateBBox( dc
, &emr
->rclBounds
);
556 HeapFree( GetProcessHeap(), 0, emr
);
560 /**********************************************************************
564 EMFDRV_PaintRgn( DC
*dc
, HRGN hrgn
)
566 return EMFDRV_PaintInvertRgn( dc
, hrgn
, EMR_PAINTRGN
);
569 /**********************************************************************
573 EMFDRV_InvertRgn( DC
*dc
, HRGN hrgn
)
575 return EMFDRV_PaintInvertRgn( dc
, hrgn
, EMR_INVERTRGN
);
578 /**********************************************************************
582 EMFDRV_SetBkColor( DC
*dc
, COLORREF color
)
586 emr
.emr
.iType
= EMR_SETBKCOLOR
;
587 emr
.emr
.nSize
= sizeof(emr
);
590 return EMFDRV_WriteRecord( dc
, &emr
.emr
);
594 /**********************************************************************
595 * EMFDRV_SetTextColor
598 EMFDRV_SetTextColor( DC
*dc
, COLORREF color
)
602 emr
.emr
.iType
= EMR_SETTEXTCOLOR
;
603 emr
.emr
.nSize
= sizeof(emr
);
606 return EMFDRV_WriteRecord( dc
, &emr
.emr
);