2 * Enhanced MetaFile driver graphics functions
4 * Copyright 1999 Huw D M Davies
11 #include "enhmetafiledrv.h"
13 #include "debugtools.h"
15 DEFAULT_DEBUG_CHANNEL(enhmetafile);
17 /**********************************************************************
21 EMFDRV_MoveTo(DC *dc, INT x, INT y)
25 emr.emr.iType = EMR_MOVETOEX;
26 emr.emr.nSize = sizeof(emr);
30 return EMFDRV_WriteRecord( dc, &emr.emr );
33 /***********************************************************************
37 EMFDRV_LineTo( DC *dc, INT x, INT y )
42 emr.emr.iType = EMR_LINETO;
43 emr.emr.nSize = sizeof(emr);
47 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
50 bounds.left = min(x, dc->CursPosX);
51 bounds.top = min(y, dc->CursPosY);
52 bounds.right = max(x, dc->CursPosX);
53 bounds.bottom = max(y, dc->CursPosY);
55 EMFDRV_UpdateBBox( dc, &bounds );
61 /***********************************************************************
65 EMFDRV_ArcChordPie( DC *dc, INT left, INT top, INT right, INT bottom,
66 INT xstart, INT ystart, INT xend, INT yend, DWORD iType )
68 INT temp, xCentre, yCentre, i;
69 double angleStart, angleEnd;
70 double xinterStart, yinterStart, xinterEnd, yinterEnd;
74 if(left == right || top == bottom) return FALSE;
76 if(left > right) {temp = left; left = right; right = temp;}
77 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
79 if(dc->GraphicsMode == GM_COMPATIBLE) {
84 emr.emr.iType = iType;
85 emr.emr.nSize = sizeof(emr);
86 emr.rclBox.left = left;
88 emr.rclBox.right = right;
89 emr.rclBox.bottom = bottom;
90 emr.ptlStart.x = xstart;
91 emr.ptlStart.y = ystart;
96 /* Now calculate the BBox */
97 xCentre = (left + right + 1) / 2;
98 yCentre = (top + bottom + 1) / 2;
105 /* invert y co-ords to get angle anti-clockwise from x-axis */
106 angleStart = atan2( -(double)ystart, (double)xstart);
107 angleEnd = atan2( -(double)yend, (double)xend);
109 /* These are the intercepts of the start/end lines with the arc */
111 xinterStart = (right - left + 1)/2 * cos(angleStart) + xCentre;
112 yinterStart = -(bottom - top + 1)/2 * sin(angleStart) + yCentre;
113 xinterEnd = (right - left + 1)/2 * cos(angleEnd) + xCentre;
114 yinterEnd = -(bottom - top + 1)/2 * sin(angleEnd) + yCentre;
116 if(angleStart < 0) angleStart += 2 * M_PI;
117 if(angleEnd < 0) angleEnd += 2 * M_PI;
118 if(angleEnd < angleStart) angleEnd += 2 * M_PI;
120 bounds.left = min(xinterStart, xinterEnd);
121 bounds.top = min(yinterStart, yinterEnd);
122 bounds.right = max(xinterStart, xinterEnd);
123 bounds.bottom = max(yinterStart, yinterEnd);
125 for(i = 0; i <= 8; i++) {
126 if(i * M_PI / 2 < angleStart) /* loop until we're past start */
128 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
131 /* the arc touches the rectangle at the start of quadrant i, so adjust
132 BBox to reflect this. */
136 bounds.right = right;
145 bounds.bottom = bottom;
150 /* If we're drawing a pie then make sure we include the centre */
151 if(iType == EMR_PIE) {
152 if(bounds.left > xCentre) bounds.left = xCentre;
153 else if(bounds.right < xCentre) bounds.right = xCentre;
154 if(bounds.top > yCentre) bounds.top = yCentre;
155 else if(bounds.bottom < yCentre) bounds.right = yCentre;
157 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
159 EMFDRV_UpdateBBox( dc, &bounds );
164 /***********************************************************************
168 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
169 INT xstart, INT ystart, INT xend, INT yend )
171 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
172 xend, yend, EMR_ARC );
175 /***********************************************************************
179 EMFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
180 INT xstart, INT ystart, INT xend, INT yend )
182 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
183 xend, yend, EMR_PIE );
187 /***********************************************************************
191 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
192 INT xstart, INT ystart, INT xend, INT yend )
194 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
195 xend, yend, EMR_CHORD );
198 /***********************************************************************
202 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
207 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
209 if(left == right || top == bottom) return FALSE;
211 if(left > right) {temp = left; left = right; right = temp;}
212 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
214 if(dc->GraphicsMode == GM_COMPATIBLE) {
219 emr.emr.iType = EMR_ELLIPSE;
220 emr.emr.nSize = sizeof(emr);
221 emr.rclBox.left = left;
222 emr.rclBox.top = top;
223 emr.rclBox.right = right;
224 emr.rclBox.bottom = bottom;
226 EMFDRV_UpdateBBox( dc, &emr.rclBox );
227 return EMFDRV_WriteRecord( dc, &emr.emr );
230 /***********************************************************************
234 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
239 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
241 if(left == right || top == bottom) return FALSE;
243 if(left > right) {temp = left; left = right; right = temp;}
244 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
246 if(dc->GraphicsMode == GM_COMPATIBLE) {
251 emr.emr.iType = EMR_RECTANGLE;
252 emr.emr.nSize = sizeof(emr);
253 emr.rclBox.left = left;
254 emr.rclBox.top = top;
255 emr.rclBox.right = right;
256 emr.rclBox.bottom = bottom;
258 EMFDRV_UpdateBBox( dc, &emr.rclBox );
259 return EMFDRV_WriteRecord( dc, &emr.emr );
262 /***********************************************************************
266 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
267 INT bottom, INT ell_width, INT ell_height )
272 if(left == right || top == bottom) return FALSE;
274 if(left > right) {temp = left; left = right; right = temp;}
275 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
277 if(dc->GraphicsMode == GM_COMPATIBLE) {
282 emr.emr.iType = EMR_ROUNDRECT;
283 emr.emr.nSize = sizeof(emr);
284 emr.rclBox.left = left;
285 emr.rclBox.top = top;
286 emr.rclBox.right = right;
287 emr.rclBox.bottom = bottom;
288 emr.szlCorner.cx = ell_width;
289 emr.szlCorner.cy = ell_height;
291 EMFDRV_UpdateBBox( dc, &emr.rclBox );
292 return EMFDRV_WriteRecord( dc, &emr.emr );
295 /***********************************************************************
299 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
305 /**********************************************************************
308 * Helper for EMFDRV_Poly{line|gon}
311 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
318 size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
320 emr = HeapAlloc( GetProcessHeap(), 0, size );
321 emr->emr.iType = iType;
322 emr->emr.nSize = size;
324 emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
325 emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
327 for(i = 1; i < count; i++) {
328 if(pt[i].x < emr->rclBounds.left)
329 emr->rclBounds.left = pt[i].x;
330 else if(pt[i].x > emr->rclBounds.right)
331 emr->rclBounds.right = pt[i].x;
332 if(pt[i].y < emr->rclBounds.top)
333 emr->rclBounds.top = pt[i].y;
334 else if(pt[i].y > emr->rclBounds.bottom)
335 emr->rclBounds.bottom = pt[i].y;
339 memcpy(emr->aptl, pt, count * sizeof(POINTL));
341 ret = EMFDRV_WriteRecord( dc, &emr->emr );
343 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
344 HeapFree( GetProcessHeap(), 0, emr );
349 /**********************************************************************
353 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
355 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
358 /**********************************************************************
362 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
364 if(count < 2) return FALSE;
365 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
369 /**********************************************************************
370 * EMFDRV_PolyPolylinegon
372 * Helper for EMFDRV_PolyPoly{line|gon}
375 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
378 EMRPOLYPOLYLINE *emr;
379 DWORD cptl = 0, poly, size, point;
384 bounds.left = bounds.right = pt[0].x;
385 bounds.top = bounds.bottom = pt[0].y;
388 for(poly = 0; poly < polys; poly++) {
389 cptl += counts[poly];
390 for(point = 0; point < counts[poly]; point++) {
391 if(bounds.left > pts->x) bounds.left = pts->x;
392 else if(bounds.right < pts->x) bounds.right = pts->x;
393 if(bounds.top > pts->y) bounds.top = pts->y;
394 else if(bounds.bottom < pts->y) bounds.bottom = pts->y;
399 size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) +
400 (cptl - 1) * sizeof(POINTL);
402 emr = HeapAlloc( GetProcessHeap(), 0, size );
404 emr->emr.iType = iType;
405 emr->emr.nSize = size;
406 emr->rclBounds = bounds;
409 memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
410 memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
411 ret = EMFDRV_WriteRecord( dc, &emr->emr );
413 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
414 HeapFree( GetProcessHeap(), 0, emr );
418 /**********************************************************************
419 * EMFDRV_PolyPolyline
422 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
424 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
428 /**********************************************************************
432 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
434 return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
438 /**********************************************************************
439 * EMFDRV_ExtFloodFill
442 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
446 emr.emr.iType = EMR_EXTFLOODFILL;
447 emr.emr.nSize = sizeof(emr);
451 emr.iMode = fillType;
453 return EMFDRV_WriteRecord( dc, &emr.emr );
457 /*********************************************************************
460 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
463 DWORD size, rgnsize, index;
466 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
467 if(!index) return FALSE;
469 rgnsize = GetRegionData( hrgn, 0, NULL );
470 size = rgnsize + sizeof(EMRFILLRGN) - 1;
471 emr = HeapAlloc( GetProcessHeap(), 0, size );
473 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
475 emr->emr.iType = EMR_FILLRGN;
476 emr->emr.nSize = size;
477 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
478 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
479 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
480 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
481 emr->cbRgnData = rgnsize;
482 emr->ihBrush = index;
484 ret = EMFDRV_WriteRecord( dc, &emr->emr );
486 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
487 HeapFree( GetProcessHeap(), 0, emr );
490 /*********************************************************************
493 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
496 DWORD size, rgnsize, index;
499 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
500 if(!index) return FALSE;
502 rgnsize = GetRegionData( hrgn, 0, NULL );
503 size = rgnsize + sizeof(EMRFRAMERGN) - 1;
504 emr = HeapAlloc( GetProcessHeap(), 0, size );
506 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
508 emr->emr.iType = EMR_FRAMERGN;
509 emr->emr.nSize = size;
510 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
511 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
512 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
513 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
514 emr->cbRgnData = rgnsize;
515 emr->ihBrush = index;
516 emr->szlStroke.cx = width;
517 emr->szlStroke.cy = height;
519 ret = EMFDRV_WriteRecord( dc, &emr->emr );
521 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
522 HeapFree( GetProcessHeap(), 0, emr );
526 /*********************************************************************
527 * EMFDRV_PaintInvertRgn
529 * Helper for EMFDRV_{Paint|Invert}Rgn
531 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
538 rgnsize = GetRegionData( hrgn, 0, NULL );
539 size = rgnsize + sizeof(EMRINVERTRGN) - 1;
540 emr = HeapAlloc( GetProcessHeap(), 0, size );
542 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
544 emr->emr.iType = iType;
545 emr->emr.nSize = size;
546 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
547 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
548 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
549 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
550 emr->cbRgnData = rgnsize;
552 ret = EMFDRV_WriteRecord( dc, &emr->emr );
554 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
555 HeapFree( GetProcessHeap(), 0, emr );
559 /**********************************************************************
563 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
565 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
568 /**********************************************************************
572 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
574 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
577 /**********************************************************************
581 EMFDRV_SetBkColor( DC *dc, COLORREF color )
585 emr.emr.iType = EMR_SETBKCOLOR;
586 emr.emr.nSize = sizeof(emr);
589 return EMFDRV_WriteRecord( dc, &emr.emr );
593 /**********************************************************************
594 * EMFDRV_SetTextColor
597 EMFDRV_SetTextColor( DC *dc, COLORREF color )
601 emr.emr.iType = EMR_SETTEXTCOLOR;
602 emr.emr.nSize = sizeof(emr);
605 return EMFDRV_WriteRecord( dc, &emr.emr );