2 * Enhanced MetaFile driver graphics functions
4 * Copyright 1999 Huw D M Davies
10 #include "enhmetafiledrv.h"
14 DEFAULT_DEBUG_CHANNEL(enhmetafile)
16 /**********************************************************************
20 EMFDRV_MoveToEx(DC *dc,INT x,INT y,LPPOINT pt)
24 emr.emr.iType = EMR_MOVETOEX;
25 emr.emr.nSize = sizeof(emr);
29 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
33 pt->x = dc->w.CursPosX;
34 pt->y = dc->w.CursPosY;
41 /***********************************************************************
45 EMFDRV_LineTo( DC *dc, INT x, INT y )
50 emr.emr.iType = EMR_LINETO;
51 emr.emr.nSize = sizeof(emr);
55 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
58 bounds.left = MIN(x, dc->w.CursPosX);
59 bounds.top = MIN(y, dc->w.CursPosY);
60 bounds.right = MAX(x, dc->w.CursPosX);
61 bounds.bottom = MAX(y, dc->w.CursPosY);
63 EMFDRV_UpdateBBox( dc, &bounds );
71 /***********************************************************************
75 EMFDRV_ArcChordPie( DC *dc, INT left, INT top, INT right, INT bottom,
76 INT xstart, INT ystart, INT xend, INT yend, DWORD iType )
78 INT temp, xCentre, yCentre, i;
79 double angleStart, angleEnd;
80 double xinterStart, yinterStart, xinterEnd, yinterEnd;
84 if(left == right || top == bottom) return FALSE;
86 if(left > right) {temp = left; left = right; right = temp;}
87 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
92 emr.emr.iType = iType;
93 emr.emr.nSize = sizeof(emr);
94 emr.rclBox.left = left;
96 emr.rclBox.right = right;
97 emr.rclBox.bottom = bottom;
98 emr.ptlStart.x = xstart;
99 emr.ptlStart.y = ystart;
104 /* Now calculate the BBox */
105 xCentre = (left + right + 1) / 2;
106 yCentre = (top + bottom + 1) / 2;
113 /* invert y co-ords to get angle anti-clockwise from x-axis */
114 angleStart = atan2( -(double)ystart, (double)xstart);
115 angleEnd = atan2( -(double)yend, (double)xend);
117 /* These are the intercepts of the start/end lines with the arc */
119 xinterStart = (right - left + 1)/2 * cos(angleStart) + xCentre;
120 yinterStart = -(bottom - top + 1)/2 * sin(angleStart) + yCentre;
121 xinterEnd = (right - left + 1)/2 * cos(angleEnd) + xCentre;
122 yinterEnd = -(bottom - top + 1)/2 * sin(angleEnd) + yCentre;
124 if(angleStart < 0) angleStart += 2 * M_PI;
125 if(angleEnd < 0) angleEnd += 2 * M_PI;
126 if(angleEnd < angleStart) angleEnd += 2 * M_PI;
128 bounds.left = MIN(xinterStart, xinterEnd);
129 bounds.top = MIN(yinterStart, yinterEnd);
130 bounds.right = MAX(xinterStart, xinterEnd);
131 bounds.bottom = MAX(yinterStart, yinterEnd);
133 for(i = 0; i <= 8; i++) {
134 if(i * M_PI / 2 < angleStart) /* loop until we're past start */
136 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
139 /* the arc touches the rectangle at the start of quadrant i, so adjust
140 BBox to reflect this. */
144 bounds.right = right;
153 bounds.bottom = bottom;
158 /* If we're drawing a pie then make sure we include the centre */
159 if(iType == EMR_PIE) {
160 if(bounds.left > xCentre) bounds.left = xCentre;
161 else if(bounds.right < xCentre) bounds.right = xCentre;
162 if(bounds.top > yCentre) bounds.top = yCentre;
163 else if(bounds.bottom < yCentre) bounds.right = yCentre;
165 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
167 EMFDRV_UpdateBBox( dc, &bounds );
172 /***********************************************************************
176 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
177 INT xstart, INT ystart, INT xend, INT yend )
179 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
180 xend, yend, EMR_ARC );
183 /***********************************************************************
187 EMFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
188 INT xstart, INT ystart, INT xend, INT yend )
190 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
191 xend, yend, EMR_PIE );
195 /***********************************************************************
199 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
200 INT xstart, INT ystart, INT xend, INT yend )
202 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
203 xend, yend, EMR_CHORD );
206 /***********************************************************************
210 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
215 TRACE(enhmetafile, "%d,%d - %d,%d\n", left, top, right, bottom);
217 if(left == right || top == bottom) return FALSE;
219 if(left > right) {temp = left; left = right; right = temp;}
220 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
225 emr.emr.iType = EMR_ELLIPSE;
226 emr.emr.nSize = sizeof(emr);
227 emr.rclBox.left = left;
228 emr.rclBox.top = top;
229 emr.rclBox.right = right;
230 emr.rclBox.bottom = bottom;
232 EMFDRV_UpdateBBox( dc, &emr.rclBox );
233 return EMFDRV_WriteRecord( dc, &emr.emr );
236 /***********************************************************************
240 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
245 TRACE(enhmetafile, "%d,%d - %d,%d\n", left, top, right, bottom);
247 if(left == right || top == bottom) return FALSE;
249 if(left > right) {temp = left; left = right; right = temp;}
250 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
255 emr.emr.iType = EMR_RECTANGLE;
256 emr.emr.nSize = sizeof(emr);
257 emr.rclBox.left = left;
258 emr.rclBox.top = top;
259 emr.rclBox.right = right;
260 emr.rclBox.bottom = bottom;
262 EMFDRV_UpdateBBox( dc, &emr.rclBox );
263 return EMFDRV_WriteRecord( dc, &emr.emr );
266 /***********************************************************************
270 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
271 INT bottom, INT ell_width, INT ell_height )
276 if(left == right || top == bottom) return FALSE;
278 if(left > right) {temp = left; left = right; right = temp;}
279 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
284 emr.emr.iType = EMR_ROUNDRECT;
285 emr.emr.nSize = sizeof(emr);
286 emr.rclBox.left = left;
287 emr.rclBox.top = top;
288 emr.rclBox.right = right;
289 emr.rclBox.bottom = bottom;
290 emr.szlCorner.cx = ell_width;
291 emr.szlCorner.cy = ell_height;
293 EMFDRV_UpdateBBox( dc, &emr.rclBox );
294 return EMFDRV_WriteRecord( dc, &emr.emr );
297 /***********************************************************************
301 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
307 /**********************************************************************
310 * Helper for EMFDRV_Poly{line|gon}
313 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
320 size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
322 emr = HeapAlloc( SystemHeap, 0, size );
323 emr->emr.iType = iType;
324 emr->emr.nSize = size;
326 emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
327 emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
329 for(i = 1; i < count; i++) {
330 if(pt[i].x < emr->rclBounds.left)
331 emr->rclBounds.left = pt[i].x;
332 else if(pt[i].x > emr->rclBounds.right)
333 emr->rclBounds.right = pt[i].x;
334 if(pt[i].y < emr->rclBounds.top)
335 emr->rclBounds.top = pt[i].y;
336 else if(pt[i].y > emr->rclBounds.bottom)
337 emr->rclBounds.bottom = pt[i].y;
341 memcpy(emr->aptl, pt, size);
343 ret = EMFDRV_WriteRecord( dc, &emr->emr );
345 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
346 HeapFree( SystemHeap, 0, emr );
351 /**********************************************************************
355 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
357 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
360 /**********************************************************************
364 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
366 if(count < 2) return FALSE;
367 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
371 /**********************************************************************
372 * EMFDRV_PolyPolylinegon
374 * Helper for EMFDRV_PolyPoly{line|gon}
377 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
380 EMRPOLYPOLYLINE *emr;
381 DWORD cptl = 0, poly, size, point;
386 bounds.left = bounds.right = pt[0].x;
387 bounds.top = bounds.bottom = pt[0].y;
390 for(poly = 0; poly < polys; poly++) {
391 cptl += counts[poly];
392 for(point = 0; point < counts[poly]; point++) {
393 if(bounds.left > pts->x) bounds.left = pts->x;
394 else if(bounds.right < pts->x) bounds.right = pts->x;
395 if(bounds.top > pts->y) bounds.top = pts->y;
396 else if(bounds.bottom < pts->y) bounds.bottom = pts->y;
401 size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) +
402 (cptl - 1) * sizeof(POINTL);
404 emr = HeapAlloc( SystemHeap, 0, size );
406 emr->emr.iType = iType;
407 emr->emr.nSize = size;
408 emr->rclBounds = bounds;
411 memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
412 memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINT));
413 ret = EMFDRV_WriteRecord( dc, &emr->emr );
415 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
416 HeapFree( SystemHeap, 0, emr );
420 /**********************************************************************
421 * EMFDRV_PolyPolyline
424 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
426 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
430 /**********************************************************************
434 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
436 return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
440 /**********************************************************************
441 * EMFDRV_ExtFloodFill
444 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
448 emr.emr.iType = EMR_EXTFLOODFILL;
449 emr.emr.nSize = sizeof(emr);
453 emr.iMode = fillType;
455 return EMFDRV_WriteRecord( dc, &emr.emr );
459 /*********************************************************************
462 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
465 DWORD size, rgnsize, index;
468 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
469 if(!index) return FALSE;
471 rgnsize = GetRegionData( hrgn, 0, NULL );
472 size = rgnsize + sizeof(EMRFILLRGN) - 1;
473 emr = HeapAlloc( SystemHeap, 0, size );
475 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
477 emr->emr.iType = EMR_FILLRGN;
478 emr->emr.nSize = size;
479 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
480 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
481 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
482 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
483 emr->cbRgnData = rgnsize;
484 emr->ihBrush = index;
486 ret = EMFDRV_WriteRecord( dc, &emr->emr );
488 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
489 HeapFree( SystemHeap, 0, emr );
492 /*********************************************************************
495 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
498 DWORD size, rgnsize, index;
501 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
502 if(!index) return FALSE;
504 rgnsize = GetRegionData( hrgn, 0, NULL );
505 size = rgnsize + sizeof(EMRFRAMERGN) - 1;
506 emr = HeapAlloc( SystemHeap, 0, size );
508 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
510 emr->emr.iType = EMR_FRAMERGN;
511 emr->emr.nSize = size;
512 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
513 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
514 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
515 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
516 emr->cbRgnData = rgnsize;
517 emr->ihBrush = index;
518 emr->szlStroke.cx = width;
519 emr->szlStroke.cy = height;
521 ret = EMFDRV_WriteRecord( dc, &emr->emr );
523 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
524 HeapFree( SystemHeap, 0, emr );
528 /*********************************************************************
529 * EMFDRV_PaintInvertRgn
531 * Helper for EMFDRV_{Paint|Invert}Rgn
533 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
540 rgnsize = GetRegionData( hrgn, 0, NULL );
541 size = rgnsize + sizeof(EMRINVERTRGN) - 1;
542 emr = HeapAlloc( SystemHeap, 0, size );
544 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
546 emr->emr.iType = iType;
547 emr->emr.nSize = size;
548 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
549 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
550 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
551 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
552 emr->cbRgnData = rgnsize;
554 ret = EMFDRV_WriteRecord( dc, &emr->emr );
556 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
557 HeapFree( SystemHeap, 0, emr );
561 /**********************************************************************
565 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
567 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
570 /**********************************************************************
574 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
576 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
579 /**********************************************************************
583 EMFDRV_SetBkColor( DC *dc, COLORREF color )
587 emr.emr.iType = EMR_SETBKCOLOR;
588 emr.emr.nSize = sizeof(emr);
591 return EMFDRV_WriteRecord( dc, &emr.emr );
595 /**********************************************************************
596 * EMFDRV_SetTextColor
599 EMFDRV_SetTextColor( DC *dc, COLORREF color )
603 emr.emr.iType = EMR_SETTEXTCOLOR;
604 emr.emr.nSize = sizeof(emr);
607 return EMFDRV_WriteRecord( dc, &emr.emr );