Added memory allocation test.
[wine/testsucceed.git] / graphics / enhmetafiledrv / graphics.c
blobb0770d25869e058106f2a4d777d038b5d2860598
1 /*
2 * Enhanced MetaFile driver graphics functions
4 * Copyright 1999 Huw D M Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdlib.h>
22 #include <string.h>
24 #include "gdi.h"
25 #include "enhmetafiledrv.h"
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(enhmetafile);
30 /**********************************************************************
31 * EMFDRV_MoveTo
33 BOOL
34 EMFDRV_MoveTo(DC *dc, INT x, INT y)
36 EMRMOVETOEX emr;
38 emr.emr.iType = EMR_MOVETOEX;
39 emr.emr.nSize = sizeof(emr);
40 emr.ptl.x = x;
41 emr.ptl.y = y;
43 return EMFDRV_WriteRecord( dc, &emr.emr );
46 /***********************************************************************
47 * EMFDRV_LineTo
49 BOOL
50 EMFDRV_LineTo( DC *dc, INT x, INT y )
52 EMRLINETO emr;
53 RECTL bounds;
55 emr.emr.iType = EMR_LINETO;
56 emr.emr.nSize = sizeof(emr);
57 emr.ptl.x = x;
58 emr.ptl.y = y;
60 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
61 return FALSE;
63 bounds.left = min(x, dc->CursPosX);
64 bounds.top = min(y, dc->CursPosY);
65 bounds.right = max(x, dc->CursPosX);
66 bounds.bottom = max(y, dc->CursPosY);
68 EMFDRV_UpdateBBox( dc, &bounds );
70 return TRUE;
74 /***********************************************************************
75 * EMFDRV_ArcChordPie
77 static BOOL
78 EMFDRV_ArcChordPie( DC *dc, INT left, INT top, INT right, INT bottom,
79 INT xstart, INT ystart, INT xend, INT yend, DWORD iType )
81 INT temp, xCentre, yCentre, i;
82 double angleStart, angleEnd;
83 double xinterStart, yinterStart, xinterEnd, yinterEnd;
84 EMRARC emr;
85 RECTL bounds;
87 if(left == right || top == bottom) return FALSE;
89 if(left > right) {temp = left; left = right; right = temp;}
90 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
92 if(dc->GraphicsMode == GM_COMPATIBLE) {
93 right--;
94 bottom--;
97 emr.emr.iType = iType;
98 emr.emr.nSize = sizeof(emr);
99 emr.rclBox.left = left;
100 emr.rclBox.top = top;
101 emr.rclBox.right = right;
102 emr.rclBox.bottom = bottom;
103 emr.ptlStart.x = xstart;
104 emr.ptlStart.y = ystart;
105 emr.ptlEnd.x = xend;
106 emr.ptlEnd.x = yend;
109 /* Now calculate the BBox */
110 xCentre = (left + right + 1) / 2;
111 yCentre = (top + bottom + 1) / 2;
113 xstart -= xCentre;
114 ystart -= yCentre;
115 xend -= xCentre;
116 yend -= yCentre;
118 /* invert y co-ords to get angle anti-clockwise from x-axis */
119 angleStart = atan2( -(double)ystart, (double)xstart);
120 angleEnd = atan2( -(double)yend, (double)xend);
122 /* These are the intercepts of the start/end lines with the arc */
124 xinterStart = (right - left + 1)/2 * cos(angleStart) + xCentre;
125 yinterStart = -(bottom - top + 1)/2 * sin(angleStart) + yCentre;
126 xinterEnd = (right - left + 1)/2 * cos(angleEnd) + xCentre;
127 yinterEnd = -(bottom - top + 1)/2 * sin(angleEnd) + yCentre;
129 if(angleStart < 0) angleStart += 2 * M_PI;
130 if(angleEnd < 0) angleEnd += 2 * M_PI;
131 if(angleEnd < angleStart) angleEnd += 2 * M_PI;
133 bounds.left = min(xinterStart, xinterEnd);
134 bounds.top = min(yinterStart, yinterEnd);
135 bounds.right = max(xinterStart, xinterEnd);
136 bounds.bottom = max(yinterStart, yinterEnd);
138 for(i = 0; i <= 8; i++) {
139 if(i * M_PI / 2 < angleStart) /* loop until we're past start */
140 continue;
141 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
142 break;
144 /* the arc touches the rectangle at the start of quadrant i, so adjust
145 BBox to reflect this. */
147 switch(i % 4) {
148 case 0:
149 bounds.right = right;
150 break;
151 case 1:
152 bounds.top = top;
153 break;
154 case 2:
155 bounds.left = left;
156 break;
157 case 3:
158 bounds.bottom = bottom;
159 break;
163 /* If we're drawing a pie then make sure we include the centre */
164 if(iType == EMR_PIE) {
165 if(bounds.left > xCentre) bounds.left = xCentre;
166 else if(bounds.right < xCentre) bounds.right = xCentre;
167 if(bounds.top > yCentre) bounds.top = yCentre;
168 else if(bounds.bottom < yCentre) bounds.right = yCentre;
170 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
171 return FALSE;
172 EMFDRV_UpdateBBox( dc, &bounds );
173 return TRUE;
177 /***********************************************************************
178 * EMFDRV_Arc
180 BOOL
181 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
182 INT xstart, INT ystart, INT xend, INT yend )
184 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
185 xend, yend, EMR_ARC );
188 /***********************************************************************
189 * EMFDRV_Pie
191 BOOL
192 EMFDRV_Pie( 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_PIE );
200 /***********************************************************************
201 * EMFDRV_Chord
203 BOOL
204 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
205 INT xstart, INT ystart, INT xend, INT yend )
207 return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
208 xend, yend, EMR_CHORD );
211 /***********************************************************************
212 * EMFDRV_Ellipse
214 BOOL
215 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
217 EMRELLIPSE emr;
218 INT temp;
220 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
222 if(left == right || top == bottom) return FALSE;
224 if(left > right) {temp = left; left = right; right = temp;}
225 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
227 if(dc->GraphicsMode == GM_COMPATIBLE) {
228 right--;
229 bottom--;
232 emr.emr.iType = EMR_ELLIPSE;
233 emr.emr.nSize = sizeof(emr);
234 emr.rclBox.left = left;
235 emr.rclBox.top = top;
236 emr.rclBox.right = right;
237 emr.rclBox.bottom = bottom;
239 EMFDRV_UpdateBBox( dc, &emr.rclBox );
240 return EMFDRV_WriteRecord( dc, &emr.emr );
243 /***********************************************************************
244 * EMFDRV_Rectangle
246 BOOL
247 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
249 EMRRECTANGLE emr;
250 INT temp;
252 TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
254 if(left == right || top == bottom) return FALSE;
256 if(left > right) {temp = left; left = right; right = temp;}
257 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
259 if(dc->GraphicsMode == GM_COMPATIBLE) {
260 right--;
261 bottom--;
264 emr.emr.iType = EMR_RECTANGLE;
265 emr.emr.nSize = sizeof(emr);
266 emr.rclBox.left = left;
267 emr.rclBox.top = top;
268 emr.rclBox.right = right;
269 emr.rclBox.bottom = bottom;
271 EMFDRV_UpdateBBox( dc, &emr.rclBox );
272 return EMFDRV_WriteRecord( dc, &emr.emr );
275 /***********************************************************************
276 * EMFDRV_RoundRect
278 BOOL
279 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
280 INT bottom, INT ell_width, INT ell_height )
282 EMRROUNDRECT emr;
283 INT temp;
285 if(left == right || top == bottom) return FALSE;
287 if(left > right) {temp = left; left = right; right = temp;}
288 if(top > bottom) {temp = top; top = bottom; bottom = temp;}
290 if(dc->GraphicsMode == GM_COMPATIBLE) {
291 right--;
292 bottom--;
295 emr.emr.iType = EMR_ROUNDRECT;
296 emr.emr.nSize = sizeof(emr);
297 emr.rclBox.left = left;
298 emr.rclBox.top = top;
299 emr.rclBox.right = right;
300 emr.rclBox.bottom = bottom;
301 emr.szlCorner.cx = ell_width;
302 emr.szlCorner.cy = ell_height;
304 EMFDRV_UpdateBBox( dc, &emr.rclBox );
305 return EMFDRV_WriteRecord( dc, &emr.emr );
308 /***********************************************************************
309 * EMFDRV_SetPixel
311 COLORREF
312 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
314 return TRUE;
318 /**********************************************************************
319 * EMFDRV_Polylinegon
321 * Helper for EMFDRV_Poly{line|gon}
323 static BOOL
324 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
326 EMRPOLYLINE *emr;
327 DWORD size;
328 INT i;
329 BOOL ret;
331 size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
333 emr = HeapAlloc( GetProcessHeap(), 0, size );
334 emr->emr.iType = iType;
335 emr->emr.nSize = size;
337 emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
338 emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
340 for(i = 1; i < count; i++) {
341 if(pt[i].x < emr->rclBounds.left)
342 emr->rclBounds.left = pt[i].x;
343 else if(pt[i].x > emr->rclBounds.right)
344 emr->rclBounds.right = pt[i].x;
345 if(pt[i].y < emr->rclBounds.top)
346 emr->rclBounds.top = pt[i].y;
347 else if(pt[i].y > emr->rclBounds.bottom)
348 emr->rclBounds.bottom = pt[i].y;
351 emr->cptl = count;
352 memcpy(emr->aptl, pt, count * sizeof(POINTL));
354 ret = EMFDRV_WriteRecord( dc, &emr->emr );
355 if(ret)
356 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
357 HeapFree( GetProcessHeap(), 0, emr );
358 return ret;
362 /**********************************************************************
363 * EMFDRV_Polyline
365 BOOL
366 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
368 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
371 /**********************************************************************
372 * EMFDRV_Polygon
374 BOOL
375 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
377 if(count < 2) return FALSE;
378 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
382 /**********************************************************************
383 * EMFDRV_PolyPolylinegon
385 * Helper for EMFDRV_PolyPoly{line|gon}
387 static BOOL
388 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
389 DWORD iType)
391 EMRPOLYPOLYLINE *emr;
392 DWORD cptl = 0, poly, size, point;
393 RECTL bounds;
394 const POINT *pts;
395 BOOL ret;
397 bounds.left = bounds.right = pt[0].x;
398 bounds.top = bounds.bottom = pt[0].y;
400 pts = pt;
401 for(poly = 0; poly < polys; poly++) {
402 cptl += counts[poly];
403 for(point = 0; point < counts[poly]; point++) {
404 if(bounds.left > pts->x) bounds.left = pts->x;
405 else if(bounds.right < pts->x) bounds.right = pts->x;
406 if(bounds.top > pts->y) bounds.top = pts->y;
407 else if(bounds.bottom < pts->y) bounds.bottom = pts->y;
408 pts++;
412 size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) +
413 (cptl - 1) * sizeof(POINTL);
415 emr = HeapAlloc( GetProcessHeap(), 0, size );
417 emr->emr.iType = iType;
418 emr->emr.nSize = size;
419 emr->rclBounds = bounds;
420 emr->nPolys = polys;
421 emr->cptl = cptl;
422 memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
423 memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
424 ret = EMFDRV_WriteRecord( dc, &emr->emr );
425 if(ret)
426 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
427 HeapFree( GetProcessHeap(), 0, emr );
428 return ret;
431 /**********************************************************************
432 * EMFDRV_PolyPolyline
434 BOOL
435 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
437 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
438 EMR_POLYPOLYLINE );
441 /**********************************************************************
442 * EMFDRV_PolyPolygon
444 BOOL
445 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
447 return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
451 /**********************************************************************
452 * EMFDRV_ExtFloodFill
454 BOOL
455 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
457 EMREXTFLOODFILL emr;
459 emr.emr.iType = EMR_EXTFLOODFILL;
460 emr.emr.nSize = sizeof(emr);
461 emr.ptlStart.x = x;
462 emr.ptlStart.y = y;
463 emr.crColor = color;
464 emr.iMode = fillType;
466 return EMFDRV_WriteRecord( dc, &emr.emr );
470 /*********************************************************************
471 * EMFDRV_FillRgn
473 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
475 EMRFILLRGN *emr;
476 DWORD size, rgnsize, index;
477 BOOL ret;
479 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
480 if(!index) return FALSE;
482 rgnsize = GetRegionData( hrgn, 0, NULL );
483 size = rgnsize + sizeof(EMRFILLRGN) - 1;
484 emr = HeapAlloc( GetProcessHeap(), 0, size );
486 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
488 emr->emr.iType = EMR_FILLRGN;
489 emr->emr.nSize = size;
490 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
491 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
492 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
493 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
494 emr->cbRgnData = rgnsize;
495 emr->ihBrush = index;
497 ret = EMFDRV_WriteRecord( dc, &emr->emr );
498 if(ret)
499 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
500 HeapFree( GetProcessHeap(), 0, emr );
501 return ret;
503 /*********************************************************************
504 * EMFDRV_FrameRgn
506 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
508 EMRFRAMERGN *emr;
509 DWORD size, rgnsize, index;
510 BOOL ret;
512 index = EMFDRV_CreateBrushIndirect( dc, hbrush );
513 if(!index) return FALSE;
515 rgnsize = GetRegionData( hrgn, 0, NULL );
516 size = rgnsize + sizeof(EMRFRAMERGN) - 1;
517 emr = HeapAlloc( GetProcessHeap(), 0, size );
519 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
521 emr->emr.iType = EMR_FRAMERGN;
522 emr->emr.nSize = size;
523 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
524 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
525 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
526 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
527 emr->cbRgnData = rgnsize;
528 emr->ihBrush = index;
529 emr->szlStroke.cx = width;
530 emr->szlStroke.cy = height;
532 ret = EMFDRV_WriteRecord( dc, &emr->emr );
533 if(ret)
534 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
535 HeapFree( GetProcessHeap(), 0, emr );
536 return ret;
539 /*********************************************************************
540 * EMFDRV_PaintInvertRgn
542 * Helper for EMFDRV_{Paint|Invert}Rgn
544 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
546 EMRINVERTRGN *emr;
547 DWORD size, rgnsize;
548 BOOL ret;
551 rgnsize = GetRegionData( hrgn, 0, NULL );
552 size = rgnsize + sizeof(EMRINVERTRGN) - 1;
553 emr = HeapAlloc( GetProcessHeap(), 0, size );
555 GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
557 emr->emr.iType = iType;
558 emr->emr.nSize = size;
559 emr->rclBounds.left = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.left;
560 emr->rclBounds.top = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.top;
561 emr->rclBounds.right = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.right - 1;
562 emr->rclBounds.bottom = ((RGNDATA *)&emr->RgnData)->rdh.rcBound.bottom - 1;
563 emr->cbRgnData = rgnsize;
565 ret = EMFDRV_WriteRecord( dc, &emr->emr );
566 if(ret)
567 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
568 HeapFree( GetProcessHeap(), 0, emr );
569 return ret;
572 /**********************************************************************
573 * EMFDRV_PaintRgn
575 BOOL
576 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
578 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
581 /**********************************************************************
582 * EMFDRV_InvertRgn
584 BOOL
585 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
587 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
590 /**********************************************************************
591 * EMFDRV_SetBkColor
593 COLORREF
594 EMFDRV_SetBkColor( DC *dc, COLORREF color )
596 EMRSETBKCOLOR emr;
598 emr.emr.iType = EMR_SETBKCOLOR;
599 emr.emr.nSize = sizeof(emr);
600 emr.crColor = color;
602 return EMFDRV_WriteRecord( dc, &emr.emr );
606 /**********************************************************************
607 * EMFDRV_SetTextColor
609 COLORREF
610 EMFDRV_SetTextColor( DC *dc, COLORREF color )
612 EMRSETTEXTCOLOR emr;
614 emr.emr.iType = EMR_SETTEXTCOLOR;
615 emr.emr.nSize = sizeof(emr);
616 emr.crColor = color;
618 return EMFDRV_WriteRecord( dc, &emr.emr );