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;}
83 emr.emr.iType = iType;
84 emr.emr.nSize = sizeof(emr);
85 emr.rclBox.left = left;
87 emr.rclBox.right = right;
88 emr.rclBox.bottom = bottom;
89 emr.ptlStart.x = xstart;
90 emr.ptlStart.y = ystart;
95 /* Now calculate the BBox */
96 xCentre = (left + right + 1) / 2;
97 yCentre = (top + bottom + 1) / 2;
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);
108 /* These are the intercepts of the start/end lines with the arc */
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;
115 if(angleStart < 0) angleStart += 2 * M_PI;
116 if(angleEnd < 0) angleEnd += 2 * M_PI;
117 if(angleEnd < angleStart) angleEnd += 2 * M_PI;
119 bounds.left = MIN(xinterStart, xinterEnd);
120 bounds.top = MIN(yinterStart, yinterEnd);
121 bounds.right = MAX(xinterStart, xinterEnd);
122 bounds.bottom = MAX(yinterStart, yinterEnd);
124 for(i = 0; i <= 8; i++) {
125 if(i * M_PI / 2 < angleStart) /* loop until we're past start */
127 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
130 /* the arc touches the rectangle at the start of quadrant i, so adjust
131 BBox to reflect this. */
135 bounds.right = right;
144 bounds.bottom = bottom;
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;
156 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
158 EMFDRV_UpdateBBox( dc, &bounds );
163 /***********************************************************************
167 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
168 INT xstart, INT ystart, INT xend, INT yend )
170 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
171 xend, yend, EMR_ARC );
174 /***********************************************************************
178 EMFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
179 INT xstart, INT ystart, INT xend, INT yend )
181 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
182 xend, yend, EMR_PIE );
186 /***********************************************************************
190 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
191 INT xstart, INT ystart, INT xend, INT yend )
193 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
194 xend, yend, EMR_CHORD );
197 /***********************************************************************
201 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
206 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
208 if(left == right || top == bottom) return FALSE;
210 if(left > right) {temp = left; left = right; right = temp;}
211 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
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;
223 EMFDRV_UpdateBBox( dc, &emr.rclBox );
224 return EMFDRV_WriteRecord( dc, &emr.emr );
227 /***********************************************************************
231 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
236 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
238 if(left == right || top == bottom) return FALSE;
240 if(left > right) {temp = left; left = right; right = temp;}
241 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
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;
253 EMFDRV_UpdateBBox( dc, &emr.rclBox );
254 return EMFDRV_WriteRecord( dc, &emr.emr );
257 /***********************************************************************
261 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
262 INT bottom, INT ell_width, INT ell_height )
267 if(left == right || top == bottom) return FALSE;
269 if(left > right) {temp = left; left = right; right = temp;}
270 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
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;
284 EMFDRV_UpdateBBox( dc, &emr.rclBox );
285 return EMFDRV_WriteRecord( dc, &emr.emr );
288 /***********************************************************************
292 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
298 /**********************************************************************
301 * Helper for EMFDRV_Poly{line|gon}
304 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
311 size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
313 emr = HeapAlloc( GetProcessHeap(), 0, size );
314 emr->emr.iType = iType;
315 emr->emr.nSize = size;
317 emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
318 emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
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;
332 memcpy(emr->aptl, pt, count * sizeof(POINTL));
334 ret = EMFDRV_WriteRecord( dc, &emr->emr );
336 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
337 HeapFree( GetProcessHeap(), 0, emr );
342 /**********************************************************************
346 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
348 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
351 /**********************************************************************
355 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
357 if(count < 2) return FALSE;
358 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
362 /**********************************************************************
363 * EMFDRV_PolyPolylinegon
365 * Helper for EMFDRV_PolyPoly{line|gon}
368 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
371 EMRPOLYPOLYLINE *emr;
372 DWORD cptl = 0, poly, size, point;
377 bounds.left = bounds.right = pt[0].x;
378 bounds.top = bounds.bottom = pt[0].y;
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;
392 size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) +
393 (cptl - 1) * sizeof(POINTL);
395 emr = HeapAlloc( GetProcessHeap(), 0, size );
397 emr->emr.iType = iType;
398 emr->emr.nSize = size;
399 emr->rclBounds = bounds;
402 memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
403 memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
404 ret = EMFDRV_WriteRecord( dc, &emr->emr );
406 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
407 HeapFree( GetProcessHeap(), 0, emr );
411 /**********************************************************************
412 * EMFDRV_PolyPolyline
415 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
417 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
421 /**********************************************************************
425 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
427 return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
431 /**********************************************************************
432 * EMFDRV_ExtFloodFill
435 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
439 emr.emr.iType = EMR_EXTFLOODFILL;
440 emr.emr.nSize = sizeof(emr);
444 emr.iMode = fillType;
446 return EMFDRV_WriteRecord( dc, &emr.emr );
450 /*********************************************************************
453 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
456 DWORD size, rgnsize, index;
459 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
460 if(!index) return FALSE;
462 rgnsize = GetRegionData( hrgn, 0, NULL );
463 size = rgnsize + sizeof(EMRFILLRGN) - 1;
464 emr = HeapAlloc( GetProcessHeap(), 0, size );
466 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
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;
477 ret = EMFDRV_WriteRecord( dc, &emr->emr );
479 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
480 HeapFree( GetProcessHeap(), 0, emr );
483 /*********************************************************************
486 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
489 DWORD size, rgnsize, index;
492 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
493 if(!index) return FALSE;
495 rgnsize = GetRegionData( hrgn, 0, NULL );
496 size = rgnsize + sizeof(EMRFRAMERGN) - 1;
497 emr = HeapAlloc( GetProcessHeap(), 0, size );
499 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
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;
512 ret = EMFDRV_WriteRecord( dc, &emr->emr );
514 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
515 HeapFree( GetProcessHeap(), 0, emr );
519 /*********************************************************************
520 * EMFDRV_PaintInvertRgn
522 * Helper for EMFDRV_{Paint|Invert}Rgn
524 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
531 rgnsize = GetRegionData( hrgn, 0, NULL );
532 size = rgnsize + sizeof(EMRINVERTRGN) - 1;
533 emr = HeapAlloc( GetProcessHeap(), 0, size );
535 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
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;
545 ret = EMFDRV_WriteRecord( dc, &emr->emr );
547 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
548 HeapFree( GetProcessHeap(), 0, emr );
552 /**********************************************************************
556 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
558 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
561 /**********************************************************************
565 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
567 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
570 /**********************************************************************
574 EMFDRV_SetBkColor( DC *dc, COLORREF color )
578 emr.emr.iType = EMR_SETBKCOLOR;
579 emr.emr.nSize = sizeof(emr);
582 return EMFDRV_WriteRecord( dc, &emr.emr );
586 /**********************************************************************
587 * EMFDRV_SetTextColor
590 EMFDRV_SetTextColor( DC *dc, COLORREF color )
594 emr.emr.iType = EMR_SETTEXTCOLOR;
595 emr.emr.nSize = sizeof(emr);
598 return EMFDRV_WriteRecord( dc, &emr.emr );