Fixed WM_GETTEXTLENGTH handling.
[wine/multimedia.git] / graphics / enhmetafiledrv / graphics.c
blobc899cd52698e9dd6c15f7c6956ac5cc4ec31f02c
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 "enhmetafiledrv.h"
12 #include "heap.h"
13 #include "debugtools.h"
15 DEFAULT_DEBUG_CHANNEL(enhmetafile);
17 /**********************************************************************
18 * EMFDRV_MoveTo
20 BOOL
21 EMFDRV_MoveTo(DC *dc, INT x, INT y)
23 EMRMOVETOEX emr;
25 emr.emr.iType = EMR_MOVETOEX;
26 emr.emr.nSize = sizeof(emr);
27 emr.ptl.x = x;
28 emr.ptl.y = y;
30 return EMFDRV_WriteRecord( dc, &emr.emr );
33 /***********************************************************************
34 * EMFDRV_LineTo
36 BOOL
37 EMFDRV_LineTo( DC *dc, INT x, INT y )
39 EMRLINETO emr;
40 RECTL bounds;
42 emr.emr.iType = EMR_LINETO;
43 emr.emr.nSize = sizeof(emr);
44 emr.ptl.x = x;
45 emr.ptl.y = y;
47 if(!EMFDRV_WriteRecord( dc, &emr.emr ))
48 return FALSE;
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 );
57 return TRUE;
61 /***********************************************************************
62 * EMFDRV_ArcChordPie
64 static BOOL
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;
71 EMRARC emr;
72 RECTL bounds;
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) {
80 right--;
81 bottom--;
84 emr.emr.iType = iType;
85 emr.emr.nSize = sizeof(emr);
86 emr.rclBox.left = left;
87 emr.rclBox.top = top;
88 emr.rclBox.right = right;
89 emr.rclBox.bottom = bottom;
90 emr.ptlStart.x = xstart;
91 emr.ptlStart.y = ystart;
92 emr.ptlEnd.x = xend;
93 emr.ptlEnd.x = yend;
96 /* Now calculate the BBox */
97 xCentre = (left + right + 1) / 2;
98 yCentre = (top + bottom + 1) / 2;
100 xstart -= xCentre;
101 ystart -= yCentre;
102 xend -= xCentre;
103 yend -= yCentre;
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 */
127 continue;
128 if(i * M_PI / 2 > angleEnd) /* if we're past end we're finished */
129 break;
131 /* the arc touches the rectangle at the start of quadrant i, so adjust
132 BBox to reflect this. */
134 switch(i % 4) {
135 case 0:
136 bounds.right = right;
137 break;
138 case 1:
139 bounds.top = top;
140 break;
141 case 2:
142 bounds.left = left;
143 break;
144 case 3:
145 bounds.bottom = bottom;
146 break;
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 ))
158 return FALSE;
159 EMFDRV_UpdateBBox( dc, &bounds );
160 return TRUE;
164 /***********************************************************************
165 * EMFDRV_Arc
167 BOOL
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 /***********************************************************************
176 * EMFDRV_Pie
178 BOOL
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 /***********************************************************************
188 * EMFDRV_Chord
190 BOOL
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 /***********************************************************************
199 * EMFDRV_Ellipse
201 BOOL
202 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
204 EMRELLIPSE emr;
205 INT temp;
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) {
215 right--;
216 bottom--;
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 /***********************************************************************
231 * EMFDRV_Rectangle
233 BOOL
234 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
236 EMRRECTANGLE emr;
237 INT temp;
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) {
247 right--;
248 bottom--;
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 /***********************************************************************
263 * EMFDRV_RoundRect
265 BOOL
266 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
267 INT bottom, INT ell_width, INT ell_height )
269 EMRROUNDRECT emr;
270 INT temp;
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) {
278 right--;
279 bottom--;
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 /***********************************************************************
296 * EMFDRV_SetPixel
298 COLORREF
299 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
301 return TRUE;
305 /**********************************************************************
306 * EMFDRV_Polylinegon
308 * Helper for EMFDRV_Poly{line|gon}
310 static BOOL
311 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
313 EMRPOLYLINE *emr;
314 DWORD size;
315 INT i;
316 BOOL ret;
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;
338 emr->cptl = count;
339 memcpy(emr->aptl, pt, count * sizeof(POINTL));
341 ret = EMFDRV_WriteRecord( dc, &emr->emr );
342 if(ret)
343 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
344 HeapFree( GetProcessHeap(), 0, emr );
345 return ret;
349 /**********************************************************************
350 * EMFDRV_Polyline
352 BOOL
353 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
355 return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
358 /**********************************************************************
359 * EMFDRV_Polygon
361 BOOL
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}
374 static BOOL
375 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
376 DWORD iType)
378 EMRPOLYPOLYLINE *emr;
379 DWORD cptl = 0, poly, size, point;
380 RECTL bounds;
381 const POINT *pts;
382 BOOL ret;
384 bounds.left = bounds.right = pt[0].x;
385 bounds.top = bounds.bottom = pt[0].y;
387 pts = pt;
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;
395 pts++;
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;
407 emr->nPolys = polys;
408 emr->cptl = cptl;
409 memcpy(emr->aPolyCounts, counts, polys * sizeof(DWORD));
410 memcpy(emr->aPolyCounts + polys, pt, cptl * sizeof(POINTL));
411 ret = EMFDRV_WriteRecord( dc, &emr->emr );
412 if(ret)
413 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
414 HeapFree( GetProcessHeap(), 0, emr );
415 return ret;
418 /**********************************************************************
419 * EMFDRV_PolyPolyline
421 BOOL
422 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
424 return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
425 EMR_POLYPOLYLINE );
428 /**********************************************************************
429 * EMFDRV_PolyPolygon
431 BOOL
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
441 BOOL
442 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
444 EMREXTFLOODFILL emr;
446 emr.emr.iType = EMR_EXTFLOODFILL;
447 emr.emr.nSize = sizeof(emr);
448 emr.ptlStart.x = x;
449 emr.ptlStart.y = y;
450 emr.crColor = color;
451 emr.iMode = fillType;
453 return EMFDRV_WriteRecord( dc, &emr.emr );
457 /*********************************************************************
458 * EMFDRV_FillRgn
460 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
462 EMRFILLRGN *emr;
463 DWORD size, rgnsize, index;
464 BOOL ret;
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 );
485 if(ret)
486 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
487 HeapFree( GetProcessHeap(), 0, emr );
488 return ret;
490 /*********************************************************************
491 * EMFDRV_FrameRgn
493 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
495 EMRFRAMERGN *emr;
496 DWORD size, rgnsize, index;
497 BOOL ret;
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 );
520 if(ret)
521 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
522 HeapFree( GetProcessHeap(), 0, emr );
523 return ret;
526 /*********************************************************************
527 * EMFDRV_PaintInvertRgn
529 * Helper for EMFDRV_{Paint|Invert}Rgn
531 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
533 EMRINVERTRGN *emr;
534 DWORD size, rgnsize;
535 BOOL ret;
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 );
553 if(ret)
554 EMFDRV_UpdateBBox( dc, &emr->rclBounds );
555 HeapFree( GetProcessHeap(), 0, emr );
556 return ret;
559 /**********************************************************************
560 * EMFDRV_PaintRgn
562 BOOL
563 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
565 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
568 /**********************************************************************
569 * EMFDRV_InvertRgn
571 BOOL
572 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
574 return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
577 /**********************************************************************
578 * EMFDRV_SetBkColor
580 COLORREF
581 EMFDRV_SetBkColor( DC *dc, COLORREF color )
583 EMRSETBKCOLOR emr;
585 emr.emr.iType = EMR_SETBKCOLOR;
586 emr.emr.nSize = sizeof(emr);
587 emr.crColor = color;
589 return EMFDRV_WriteRecord( dc, &emr.emr );
593 /**********************************************************************
594 * EMFDRV_SetTextColor
596 COLORREF
597 EMFDRV_SetTextColor( DC *dc, COLORREF color )
599 EMRSETTEXTCOLOR emr;
601 emr.emr.iType = EMR_SETTEXTCOLOR;
602 emr.emr.nSize = sizeof(emr);
603 emr.crColor = color;
605 return EMFDRV_WriteRecord( dc, &emr.emr );