Moved all the documented shlwapi functions out of undocshell.h into
[wine] / graphics / enhmetafiledrv / graphics.c
1 /*
2  * Enhanced MetaFile driver graphics functions
3  *
4  * Copyright 1999 Huw D M Davies
5  */
6
7 #include <stdlib.h>
8 #include <string.h>
9
10 #include "gdi.h"
11 #include "enhmetafiledrv.h"
12 #include "heap.h"
13 #include "debugtools.h"
14
15 DEFAULT_DEBUG_CHANNEL(enhmetafile);
16
17 /**********************************************************************
18  *           EMFDRV_MoveTo
19  */
20 BOOL
21 EMFDRV_MoveTo(DC *dc, INT x, INT y)
22 {
23     EMRMOVETOEX emr;
24
25     emr.emr.iType = EMR_MOVETOEX;
26     emr.emr.nSize = sizeof(emr);
27     emr.ptl.x = x;
28     emr.ptl.y = y;
29
30     return EMFDRV_WriteRecord( dc, &emr.emr );
31 }
32
33 /***********************************************************************
34  *           EMFDRV_LineTo
35  */
36 BOOL
37 EMFDRV_LineTo( DC *dc, INT x, INT y )
38 {
39     EMRLINETO emr;
40     RECTL bounds;
41
42     emr.emr.iType = EMR_LINETO;
43     emr.emr.nSize = sizeof(emr);
44     emr.ptl.x = x;
45     emr.ptl.y = y;
46
47     if(!EMFDRV_WriteRecord( dc, &emr.emr ))
48         return FALSE;
49
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);
54
55     EMFDRV_UpdateBBox( dc, &bounds );
56
57     return TRUE;
58 }
59
60
61 /***********************************************************************
62  *           EMFDRV_ArcChordPie
63  */
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 )
67 {
68     INT temp, xCentre, yCentre, i;
69     double angleStart, angleEnd;
70     double xinterStart, yinterStart, xinterEnd, yinterEnd;
71     EMRARC emr;
72     RECTL bounds;
73
74     if(left == right || top == bottom) return FALSE;
75
76     if(left > right) {temp = left; left = right; right = temp;}
77     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
78
79     if(dc->GraphicsMode == GM_COMPATIBLE) {
80         right--;
81         bottom--;
82     }
83
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;
94
95
96     /* Now calculate the BBox */
97     xCentre = (left + right + 1) / 2;
98     yCentre = (top + bottom + 1) / 2;
99
100     xstart -= xCentre;
101     ystart -= yCentre;
102     xend   -= xCentre;
103     yend   -= yCentre;
104
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);
108
109     /* These are the intercepts of the start/end lines with the arc */
110
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;
115
116     if(angleStart < 0) angleStart += 2 * M_PI;
117     if(angleEnd < 0) angleEnd += 2 * M_PI;
118     if(angleEnd < angleStart) angleEnd += 2 * M_PI;
119
120     bounds.left   = min(xinterStart, xinterEnd);
121     bounds.top    = min(yinterStart, yinterEnd);
122     bounds.right  = max(xinterStart, xinterEnd);
123     bounds.bottom = max(yinterStart, yinterEnd);
124     
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;
130
131         /* the arc touches the rectangle at the start of quadrant i, so adjust
132            BBox to reflect this. */
133
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;
147         }
148     }
149
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;
156     }
157     if(!EMFDRV_WriteRecord( dc, &emr.emr ))
158         return FALSE;
159     EMFDRV_UpdateBBox( dc, &bounds );
160     return TRUE;
161 }
162
163
164 /***********************************************************************
165  *           EMFDRV_Arc
166  */
167 BOOL
168 EMFDRV_Arc( DC *dc, INT left, INT top, INT right, INT bottom,
169             INT xstart, INT ystart, INT xend, INT yend )
170 {
171     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
172                                xend, yend, EMR_ARC );
173 }
174
175 /***********************************************************************
176  *           EMFDRV_Pie
177  */
178 BOOL
179 EMFDRV_Pie( DC *dc, INT left, INT top, INT right, INT bottom,
180             INT xstart, INT ystart, INT xend, INT yend )
181 {
182     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
183                                xend, yend, EMR_PIE );
184 }
185
186
187 /***********************************************************************
188  *           EMFDRV_Chord
189  */
190 BOOL
191 EMFDRV_Chord( DC *dc, INT left, INT top, INT right, INT bottom,
192              INT xstart, INT ystart, INT xend, INT yend )
193 {
194     return EMFDRV_ArcChordPie( dc, left, top, right, bottom, xstart, ystart,
195                                xend, yend, EMR_CHORD );
196 }
197
198 /***********************************************************************
199  *           EMFDRV_Ellipse
200  */
201 BOOL
202 EMFDRV_Ellipse( DC *dc, INT left, INT top, INT right, INT bottom )
203 {
204     EMRELLIPSE emr;
205     INT temp;
206
207     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
208
209     if(left == right || top == bottom) return FALSE;
210
211     if(left > right) {temp = left; left = right; right = temp;}
212     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
213
214     if(dc->GraphicsMode == GM_COMPATIBLE) {
215         right--;
216         bottom--;
217     }
218
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;
225
226     EMFDRV_UpdateBBox( dc, &emr.rclBox );
227     return EMFDRV_WriteRecord( dc, &emr.emr );
228 }
229
230 /***********************************************************************
231  *           EMFDRV_Rectangle
232  */
233 BOOL
234 EMFDRV_Rectangle(DC *dc, INT left, INT top, INT right, INT bottom)
235 {
236     EMRRECTANGLE emr;
237     INT temp;
238
239     TRACE("%d,%d - %d,%d\n", left, top, right, bottom);
240
241     if(left == right || top == bottom) return FALSE;
242
243     if(left > right) {temp = left; left = right; right = temp;}
244     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
245
246     if(dc->GraphicsMode == GM_COMPATIBLE) {
247         right--;
248         bottom--;
249     }
250
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;
257
258     EMFDRV_UpdateBBox( dc, &emr.rclBox );
259     return EMFDRV_WriteRecord( dc, &emr.emr );
260 }
261
262 /***********************************************************************
263  *           EMFDRV_RoundRect
264  */
265 BOOL 
266 EMFDRV_RoundRect( DC *dc, INT left, INT top, INT right,
267                   INT bottom, INT ell_width, INT ell_height )
268 {
269     EMRROUNDRECT emr;
270     INT temp;
271
272     if(left == right || top == bottom) return FALSE;
273
274     if(left > right) {temp = left; left = right; right = temp;}
275     if(top > bottom) {temp = top; top = bottom; bottom = temp;}
276
277     if(dc->GraphicsMode == GM_COMPATIBLE) {
278         right--;
279         bottom--;
280     }
281
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;
290
291     EMFDRV_UpdateBBox( dc, &emr.rclBox );
292     return EMFDRV_WriteRecord( dc, &emr.emr );
293 }
294
295 /***********************************************************************
296  *           EMFDRV_SetPixel
297  */
298 COLORREF
299 EMFDRV_SetPixel( DC *dc, INT x, INT y, COLORREF color )
300 {
301   return TRUE;
302 }
303
304
305 /**********************************************************************
306  *          EMFDRV_Polylinegon
307  *
308  * Helper for EMFDRV_Poly{line|gon}
309  */
310 static BOOL
311 EMFDRV_Polylinegon( DC *dc, const POINT* pt, INT count, DWORD iType )
312 {
313     EMRPOLYLINE *emr;
314     DWORD size;
315     INT i;
316     BOOL ret;
317
318     size = sizeof(EMRPOLYLINE) + sizeof(POINTL) * (count - 1);
319
320     emr = HeapAlloc( GetProcessHeap(), 0, size );
321     emr->emr.iType = iType;
322     emr->emr.nSize = size;
323     
324     emr->rclBounds.left = emr->rclBounds.right = pt[0].x;
325     emr->rclBounds.top = emr->rclBounds.bottom = pt[0].y;
326
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;
336     }
337
338     emr->cptl = count;
339     memcpy(emr->aptl, pt, count * sizeof(POINTL));
340
341     ret = EMFDRV_WriteRecord( dc, &emr->emr );
342     if(ret)
343         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
344     HeapFree( GetProcessHeap(), 0, emr );
345     return ret;
346 }
347
348
349 /**********************************************************************
350  *          EMFDRV_Polyline
351  */
352 BOOL
353 EMFDRV_Polyline( DC *dc, const POINT* pt, INT count )
354 {
355     return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYLINE );
356 }
357
358 /**********************************************************************
359  *          EMFDRV_Polygon
360  */
361 BOOL
362 EMFDRV_Polygon( DC *dc, const POINT* pt, INT count )
363 {
364     if(count < 2) return FALSE;
365     return EMFDRV_Polylinegon( dc, pt, count, EMR_POLYGON );
366 }
367
368
369 /**********************************************************************
370  *          EMFDRV_PolyPolylinegon
371  *
372  * Helper for EMFDRV_PolyPoly{line|gon}
373  */
374 static BOOL 
375 EMFDRV_PolyPolylinegon( DC *dc, const POINT* pt, const INT* counts, UINT polys,
376                         DWORD iType)
377 {
378     EMRPOLYPOLYLINE *emr;
379     DWORD cptl = 0, poly, size, point;
380     RECTL bounds;
381     const POINT *pts;
382     BOOL ret;
383
384     bounds.left = bounds.right = pt[0].x;
385     bounds.top = bounds.bottom = pt[0].y;
386
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++;
396         }
397     }
398     
399     size = sizeof(EMRPOLYPOLYLINE) + (polys - 1) * sizeof(DWORD) + 
400       (cptl - 1) * sizeof(POINTL);
401
402     emr = HeapAlloc( GetProcessHeap(), 0, size );
403
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;
416 }
417
418 /**********************************************************************
419  *          EMFDRV_PolyPolyline
420  */
421 BOOL 
422 EMFDRV_PolyPolyline(DC *dc, const POINT* pt, const DWORD* counts, DWORD polys)
423 {
424     return EMFDRV_PolyPolylinegon( dc, pt, (INT *)counts, polys,
425                                    EMR_POLYPOLYLINE );
426 }
427
428 /**********************************************************************
429  *          EMFDRV_PolyPolygon
430  */
431 BOOL 
432 EMFDRV_PolyPolygon( DC *dc, const POINT* pt, const INT* counts, UINT polys )
433 {
434     return EMFDRV_PolyPolylinegon( dc, pt, counts, polys, EMR_POLYPOLYGON );
435 }
436
437
438 /**********************************************************************
439  *          EMFDRV_ExtFloodFill
440  */
441 BOOL 
442 EMFDRV_ExtFloodFill( DC *dc, INT x, INT y, COLORREF color, UINT fillType )
443 {
444     EMREXTFLOODFILL emr;
445
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;
452
453     return EMFDRV_WriteRecord( dc, &emr.emr );
454 }
455
456
457 /*********************************************************************
458  *          EMFDRV_FillRgn
459  */
460 BOOL EMFDRV_FillRgn( DC *dc, HRGN hrgn, HBRUSH hbrush )
461 {
462     EMRFILLRGN *emr;
463     DWORD size, rgnsize, index;
464     BOOL ret;
465
466     index = EMFDRV_CreateBrushIndirect( dc, hbrush );
467     if(!index) return FALSE;
468
469     rgnsize = GetRegionData( hrgn, 0, NULL );
470     size = rgnsize + sizeof(EMRFILLRGN) - 1;
471     emr = HeapAlloc( GetProcessHeap(), 0, size );
472
473     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
474
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;
483     
484     ret = EMFDRV_WriteRecord( dc, &emr->emr );
485     if(ret)
486         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
487     HeapFree( GetProcessHeap(), 0, emr );
488     return ret;
489 }
490 /*********************************************************************
491  *          EMFDRV_FrameRgn
492  */
493 BOOL EMFDRV_FrameRgn( DC *dc, HRGN hrgn, HBRUSH hbrush, INT width, INT height )
494 {
495     EMRFRAMERGN *emr;
496     DWORD size, rgnsize, index;
497     BOOL ret;
498
499     index = EMFDRV_CreateBrushIndirect( dc, hbrush );
500     if(!index) return FALSE;
501
502     rgnsize = GetRegionData( hrgn, 0, NULL );
503     size = rgnsize + sizeof(EMRFRAMERGN) - 1;
504     emr = HeapAlloc( GetProcessHeap(), 0, size );
505
506     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
507
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;
518
519     ret = EMFDRV_WriteRecord( dc, &emr->emr );
520     if(ret)
521         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
522     HeapFree( GetProcessHeap(), 0, emr );
523     return ret;
524 }
525
526 /*********************************************************************
527  *          EMFDRV_PaintInvertRgn
528  *
529  * Helper for EMFDRV_{Paint|Invert}Rgn
530  */
531 static BOOL EMFDRV_PaintInvertRgn( DC *dc, HRGN hrgn, DWORD iType )
532 {
533     EMRINVERTRGN *emr;
534     DWORD size, rgnsize;
535     BOOL ret;
536
537
538     rgnsize = GetRegionData( hrgn, 0, NULL );
539     size = rgnsize + sizeof(EMRINVERTRGN) - 1;
540     emr = HeapAlloc( GetProcessHeap(), 0, size );
541
542     GetRegionData( hrgn, rgnsize, (RGNDATA *)&emr->RgnData );
543
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;
551     
552     ret = EMFDRV_WriteRecord( dc, &emr->emr );
553     if(ret)
554         EMFDRV_UpdateBBox( dc, &emr->rclBounds );
555     HeapFree( GetProcessHeap(), 0, emr );
556     return ret;
557 }
558
559 /**********************************************************************
560  *          EMFDRV_PaintRgn
561  */
562 BOOL
563 EMFDRV_PaintRgn( DC *dc, HRGN hrgn )
564 {
565     return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_PAINTRGN );
566 }
567
568 /**********************************************************************
569  *          EMFDRV_InvertRgn
570  */
571 BOOL
572 EMFDRV_InvertRgn( DC *dc, HRGN hrgn )
573 {
574     return EMFDRV_PaintInvertRgn( dc, hrgn, EMR_INVERTRGN );
575 }
576
577 /**********************************************************************
578  *          EMFDRV_SetBkColor
579  */
580 COLORREF
581 EMFDRV_SetBkColor( DC *dc, COLORREF color )
582 {
583     EMRSETBKCOLOR emr;
584
585     emr.emr.iType = EMR_SETBKCOLOR;
586     emr.emr.nSize = sizeof(emr);
587     emr.crColor = color;
588
589     return EMFDRV_WriteRecord( dc, &emr.emr );
590 }
591
592
593 /**********************************************************************
594  *          EMFDRV_SetTextColor
595  */
596 COLORREF
597 EMFDRV_SetTextColor( DC *dc, COLORREF color )
598 {
599     EMRSETTEXTCOLOR emr;
600
601     emr.emr.iType = EMR_SETTEXTCOLOR;
602     emr.emr.nSize = sizeof(emr);
603     emr.crColor = color;
604
605     return EMFDRV_WriteRecord( dc, &emr.emr );
606 }