Moved SystemHeap allocations to the process heap.
[wine.git] / graphics / enhmetafiledrv / graphics.c
blobe83c7a06c15c0ed838331a95cb01d1e49b213bdd
1 /*
2 * Enhanced MetaFile driver graphics functions
4 * Copyright 1999 Huw D M Davies
5 */
7 #include <stdlib.h>
8 #include <string.h>
10 #include "gdi.h"
11 #include "dc.h"
12 #include "enhmetafiledrv.h"
13 #include "heap.h"
14 #include "debugtools.h"
16 DEFAULT_DEBUG_CHANNEL(enhmetafile)
18 /**********************************************************************
19 * EMFDRV_MoveToEx
21 BOOL
22 EMFDRV_MoveToEx(DC *dc,INT x,INT y,LPPOINT pt)
24 EMRMOVETOEX emr;
26 emr.emr.iType = EMR_MOVETOEX;
27 emr.emr.nSize = sizeof(emr);
28 emr.ptl.x = x;
29 emr.ptl.y = y;
31 return EMFDRV_WriteRecord( dc, &emr.emr );
34 /***********************************************************************
35 * EMFDRV_LineTo
37 BOOL
38 EMFDRV_LineTo( DC *dc, INT x, INT y )
40 EMRLINETO emr;
41 RECTL bounds;
43 emr.emr.iType = EMR_LINETO;
44 emr.emr.nSize = sizeof(emr);
45 emr.ptl.x = x;
46 emr.ptl.y = y;
48 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
49 return FALSE;
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 );
58 return TRUE;
62 /***********************************************************************
63 * EMFDRV_ArcChordPie
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 )
69 INT temp, xCentre, yCentre, i;
70 double angleStart, angleEnd;
71 double xinterStart, yinterStart, xinterEnd, yinterEnd;
72 EMRARC emr;
73 RECTL bounds;
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 right--;
81 bottom--;
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;
95 /* Now calculate the BBox */
96 xCentre = (left + right + 1) / 2;
97 yCentre = (top + bottom + 1) / 2;
99 xstart -= xCentre;
100 ystart -= yCentre;
101 xend -= xCentre;
102 yend -= yCentre;
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 */
126 continue;
127 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
128 break;
130 /* the arc touches the rectangle at the start of quadrant i, so adjust
131 BBox to reflect this. */
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;
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 ))
157 return FALSE;
158 EMFDRV_UpdateBBox( dc, &bounds );
159 return TRUE;
163 /***********************************************************************
164 * EMFDRV_Arc
166 BOOL
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 /***********************************************************************
175 * EMFDRV_Pie
177 BOOL
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 /***********************************************************************
187 * EMFDRV_Chord
189 BOOL
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 /***********************************************************************
198 * EMFDRV_Ellipse
200 BOOL
201 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
203 EMRELLIPSE emr;
204 INT temp;
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;}
213 right--;
214 bottom--;
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 /***********************************************************************
228 * EMFDRV_Rectangle
230 BOOL
231 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
233 EMRRECTANGLE emr;
234 INT temp;
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;}
243 right--;
244 bottom--;
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 /***********************************************************************
258 * EMFDRV_RoundRect
260 BOOL
261 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
262 INT bottom, INT ell_width, INT ell_height )
264 EMRROUNDRECT emr;
265 INT temp;
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;}
272 right--;
273 bottom--;
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 /***********************************************************************
289 * EMFDRV_SetPixel
291 COLORREF
292 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
294 return TRUE;
298 /**********************************************************************
299 * EMFDRV_Polylinegon
301 * Helper for EMFDRV_Poly{line|gon}
303 static BOOL
304 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
306 EMRPOLYLINE *emr;
307 DWORD size;
308 INT i;
309 BOOL ret;
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;
331 emr->cptl = count;
332 memcpy(emr->aptl, pt, count * sizeof(POINTL));
334 ret = EMFDRV_WriteRecord( dc, &emr->emr );
335 if(ret)
336 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
337 HeapFree( GetProcessHeap(), 0, emr );
338 return ret;
342 /**********************************************************************
343 * EMFDRV_Polyline
345 BOOL
346 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
348 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
351 /**********************************************************************
352 * EMFDRV_Polygon
354 BOOL
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}
367 static BOOL
368 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
369 DWORD iType)
371 EMRPOLYPOLYLINE *emr;
372 DWORD cptl = 0, poly, size, point;
373 RECTL bounds;
374 const POINT *pts;
375 BOOL ret;
377 bounds.left = bounds.right = pt[0].x;
378 bounds.top = bounds.bottom = pt[0].y;
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++;
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;
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;
411 /**********************************************************************
412 * EMFDRV_PolyPolyline
414 BOOL
415 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
417 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
418 EMR_POLYPOLYLINE );
421 /**********************************************************************
422 * EMFDRV_PolyPolygon
424 BOOL
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
434 BOOL
435 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
437 EMREXTFLOODFILL emr;
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;
446 return EMFDRV_WriteRecord( dc, &emr.emr );
450 /*********************************************************************
451 * EMFDRV_FillRgn
453 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
455 EMRFILLRGN *emr;
456 DWORD size, rgnsize, index;
457 BOOL ret;
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 );
478 if(ret)
479 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
480 HeapFree( GetProcessHeap(), 0, emr );
481 return ret;
483 /*********************************************************************
484 * EMFDRV_FrameRgn
486 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
488 EMRFRAMERGN *emr;
489 DWORD size, rgnsize, index;
490 BOOL ret;
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 );
513 if(ret)
514 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
515 HeapFree( GetProcessHeap(), 0, emr );
516 return ret;
519 /*********************************************************************
520 * EMFDRV_PaintInvertRgn
522 * Helper for EMFDRV_{Paint|Invert}Rgn
524 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
526 EMRINVERTRGN *emr;
527 DWORD size, rgnsize;
528 BOOL ret;
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 );
546 if(ret)
547 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
548 HeapFree( GetProcessHeap(), 0, emr );
549 return ret;
552 /**********************************************************************
553 * EMFDRV_PaintRgn
555 BOOL
556 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
558 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
561 /**********************************************************************
562 * EMFDRV_InvertRgn
564 BOOL
565 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
567 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
570 /**********************************************************************
571 * EMFDRV_SetBkColor
573 COLORREF
574 EMFDRV_SetBkColor( DC *dc, COLORREF color )
576 EMRSETBKCOLOR emr;
578 emr.emr.iType = EMR_SETBKCOLOR;
579 emr.emr.nSize = sizeof(emr);
580 emr.crColor = color;
582 return EMFDRV_WriteRecord( dc, &emr.emr );
586 /**********************************************************************
587 * EMFDRV_SetTextColor
589 COLORREF
590 EMFDRV_SetTextColor( DC *dc, COLORREF color )
592 EMRSETTEXTCOLOR emr;
594 emr.emr.iType = EMR_SETTEXTCOLOR;
595 emr.emr.nSize = sizeof(emr);
596 emr.crColor = color;
598 return EMFDRV_WriteRecord( dc, &emr.emr );