- change the internal functions in windows/cursoricon.c to use 32bit
[wine] / graphics / painting.c
1 /*
2  * GDI drawing functions.
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  * Copyright 1997 Bertho A. Stultiens
6  *           1999 Huw D M Davies
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include "windef.h"
30 #include "wingdi.h"
31 #include "winerror.h"
32 #include "gdi.h"
33 #include "bitmap.h"
34 #include "path.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
38
39
40 /***********************************************************************
41  *           LineTo    (GDI32.@)
42  */
43 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
44 {
45     DC * dc = DC_GetDCUpdate( hdc );
46     BOOL ret;
47
48     if(!dc) return FALSE;
49
50     if(PATH_IsPathOpen(dc->path))
51         ret = PATH_LineTo(dc, x, y);
52     else
53         ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
54     if(ret) {
55         dc->CursPosX = x;
56         dc->CursPosY = y;
57     }
58     GDI_ReleaseObj( hdc );
59     return ret;
60 }
61
62
63 /***********************************************************************
64  *           MoveToEx    (GDI32.@)
65  */
66 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
67 {
68     BOOL ret = TRUE;
69     DC * dc = DC_GetDCPtr( hdc );
70
71     if(!dc) return FALSE;
72
73     if(pt) {
74         pt->x = dc->CursPosX;
75         pt->y = dc->CursPosY;
76     }
77     dc->CursPosX = x;
78     dc->CursPosY = y;
79
80     if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
81     else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
82     GDI_ReleaseObj( hdc );
83     return ret;
84 }
85
86
87 /***********************************************************************
88  *           Arc    (GDI32.@)
89  */
90 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
91                      INT bottom, INT xstart, INT ystart,
92                      INT xend, INT yend )
93 {
94     BOOL ret = FALSE;
95     DC * dc = DC_GetDCUpdate( hdc );
96     if (dc)
97     {
98     if(PATH_IsPathOpen(dc->path))
99             ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
100         else if (dc->funcs->pArc)
101             ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
102         GDI_ReleaseObj( hdc );
103     }
104     return ret;
105 }
106
107 /***********************************************************************
108  *           ArcTo    (GDI32.@)
109  */
110 BOOL WINAPI ArcTo( HDC hdc,
111                      INT left,   INT top,
112                      INT right,  INT bottom,
113                      INT xstart, INT ystart,
114                      INT xend,   INT yend )
115 {
116     BOOL result;
117     DC * dc = DC_GetDCUpdate( hdc );
118     if(!dc) return FALSE;
119
120     if(dc->funcs->pArcTo)
121     {
122         result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
123                                   xstart, ystart, xend, yend );
124         GDI_ReleaseObj( hdc );
125         return result;
126     }
127     GDI_ReleaseObj( hdc );
128     /*
129      * Else emulate it.
130      * According to the documentation, a line is drawn from the current
131      * position to the starting point of the arc.
132      */
133     LineTo(hdc, xstart, ystart);
134     /*
135      * Then the arc is drawn.
136      */
137     result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
138     /*
139      * If no error occurred, the current position is moved to the ending
140      * point of the arc.
141      */
142     if (result) MoveToEx(hdc, xend, yend, NULL);
143     return result;
144 }
145
146
147 /***********************************************************************
148  *           Pie   (GDI32.@)
149  */
150 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
151                      INT right, INT bottom, INT xstart, INT ystart,
152                      INT xend, INT yend )
153 {
154     BOOL ret = FALSE;
155     DC * dc = DC_GetDCUpdate( hdc );
156     if (!dc) return FALSE;
157
158     if(PATH_IsPathOpen(dc->path))
159         ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
160     else if(dc->funcs->pPie)
161         ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
162
163     GDI_ReleaseObj( hdc );
164     return ret;
165 }
166
167
168 /***********************************************************************
169  *           Chord    (GDI32.@)
170  */
171 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
172                        INT right, INT bottom, INT xstart, INT ystart,
173                        INT xend, INT yend )
174 {
175     BOOL ret = FALSE;
176     DC * dc = DC_GetDCUpdate( hdc );
177     if (!dc) return FALSE;
178
179     if(PATH_IsPathOpen(dc->path))
180         ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
181     else if(dc->funcs->pChord)
182         ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
183
184     GDI_ReleaseObj( hdc );
185     return ret;
186 }
187
188
189 /***********************************************************************
190  *           Ellipse    (GDI32.@)
191  */
192 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
193                          INT right, INT bottom )
194 {
195     BOOL ret = FALSE;
196     DC * dc = DC_GetDCUpdate( hdc );
197     if (!dc) return FALSE;
198
199     if(PATH_IsPathOpen(dc->path))
200         ret = PATH_Ellipse(dc,left,top,right,bottom);
201     else if (dc->funcs->pEllipse)
202         ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
203
204     GDI_ReleaseObj( hdc );
205     return ret;
206 }
207
208
209 /***********************************************************************
210  *           Rectangle    (GDI32.@)
211  */
212 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
213                            INT right, INT bottom )
214 {
215     BOOL ret = FALSE;
216     DC * dc = DC_GetDCUpdate( hdc );
217     if (dc)
218     {
219     if(PATH_IsPathOpen(dc->path))
220             ret = PATH_Rectangle(dc, left, top, right, bottom);
221         else if (dc->funcs->pRectangle)
222             ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
223         GDI_ReleaseObj( hdc );
224     }
225     return ret;
226 }
227
228
229 /***********************************************************************
230  *           RoundRect    (GDI32.@)
231  */
232 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
233                            INT bottom, INT ell_width, INT ell_height )
234 {
235     BOOL ret = FALSE;
236     DC *dc = DC_GetDCUpdate( hdc );
237
238     if (dc)
239     {
240         if(PATH_IsPathOpen(dc->path))
241             ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
242         else if (dc->funcs->pRoundRect)
243             ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
244         GDI_ReleaseObj( hdc );
245     }
246     return ret;
247 }
248
249 /***********************************************************************
250  *           SetPixel    (GDI32.@)
251  */
252 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
253 {
254     COLORREF ret = 0;
255     DC * dc = DC_GetDCUpdate( hdc );
256     if (dc)
257     {
258         if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
259         GDI_ReleaseObj( hdc );
260     }
261     return ret;
262 }
263
264 /***********************************************************************
265  *           SetPixelV    (GDI32.@)
266  */
267 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
268 {
269     BOOL ret = FALSE;
270     DC * dc = DC_GetDCUpdate( hdc );
271     if (dc)
272     {
273         if (dc->funcs->pSetPixel)
274         {
275             dc->funcs->pSetPixel(dc->physDev,x,y,color);
276             ret = TRUE;
277         }
278         GDI_ReleaseObj( hdc );
279     }
280     return ret;
281 }
282
283 /***********************************************************************
284  *           GetPixel    (GDI32.@)
285  */
286 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
287 {
288     COLORREF ret = CLR_INVALID;
289     DC * dc = DC_GetDCUpdate( hdc );
290
291     if (dc)
292     {
293     /* FIXME: should this be in the graphics driver? */
294         if (PtVisible( hdc, x, y ))
295         {
296             if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
297         }
298         GDI_ReleaseObj( hdc );
299     }
300     return ret;
301 }
302
303
304 /******************************************************************************
305  * ChoosePixelFormat [GDI32.@]
306  * Matches a pixel format to given format
307  *
308  * PARAMS
309  *    hdc  [I] Device context to search for best pixel match
310  *    ppfd [I] Pixel format for which a match is sought
311  *
312  * RETURNS
313  *    Success: Pixel format index closest to given format
314  *    Failure: 0
315  */
316 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
317 {
318     INT ret = 0;
319     DC * dc = DC_GetDCPtr( hdc );
320
321     TRACE("(%08x,%p)\n",hdc,ppfd);
322
323     if (!dc) return 0;
324
325     if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
326     else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
327
328     GDI_ReleaseObj( hdc );
329     return ret;
330 }
331
332
333 /******************************************************************************
334  * SetPixelFormat [GDI32.@]
335  * Sets pixel format of device context
336  *
337  * PARAMS
338  *    hdc          [I] Device context to search for best pixel match
339  *    iPixelFormat [I] Pixel format index
340  *    ppfd         [I] Pixel format for which a match is sought
341  *
342  * RETURNS STD
343  */
344 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
345                             const PIXELFORMATDESCRIPTOR *ppfd)
346 {
347     INT bRet = FALSE;
348     DC * dc = DC_GetDCPtr( hdc );
349
350     TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
351
352     if (!dc) return 0;
353
354     if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
355     else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
356
357     GDI_ReleaseObj( hdc );
358     return bRet;
359 }
360
361
362 /******************************************************************************
363  * GetPixelFormat [GDI32.@]
364  * Gets index of pixel format of DC
365  *
366  * PARAMETERS
367  *    hdc [I] Device context whose pixel format index is sought
368  *
369  * RETURNS
370  *    Success: Currently selected pixel format
371  *    Failure: 0
372  */
373 INT WINAPI GetPixelFormat( HDC hdc )
374 {
375     INT ret = 0;
376     DC * dc = DC_GetDCPtr( hdc );
377
378     TRACE("(%08x)\n",hdc);
379
380     if (!dc) return 0;
381
382     if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
383     else ret = dc->funcs->pGetPixelFormat(dc->physDev);
384
385     GDI_ReleaseObj( hdc );
386     return ret;
387 }
388
389
390 /******************************************************************************
391  * DescribePixelFormat [GDI32.@]
392  * Gets info about pixel format from DC
393  *
394  * PARAMS
395  *    hdc          [I] Device context
396  *    iPixelFormat [I] Pixel format selector
397  *    nBytes       [I] Size of buffer
398  *    ppfd         [O] Pointer to structure to receive pixel format data
399  *
400  * RETURNS
401  *    Success: Maximum pixel format index of the device context
402  *    Failure: 0
403  */
404 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
405                                 LPPIXELFORMATDESCRIPTOR ppfd )
406 {
407     INT ret = 0;
408     DC * dc = DC_GetDCPtr( hdc );
409
410     TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
411
412     if (!dc) return 0;
413
414     if (!dc->funcs->pDescribePixelFormat)
415     {
416         FIXME(" :stub\n");
417         ppfd->nSize = nBytes;
418         ppfd->nVersion = 1;
419         ret = 3;
420     }
421     else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
422
423     GDI_ReleaseObj( hdc );
424     return ret;
425 }
426
427
428 /******************************************************************************
429  * SwapBuffers [GDI32.@]
430  * Exchanges front and back buffers of window
431  *
432  * PARAMS
433  *    hdc [I] Device context whose buffers get swapped
434  *
435  * RETURNS STD
436  */
437 BOOL WINAPI SwapBuffers( HDC hdc )
438 {
439     INT bRet = FALSE;
440     DC * dc = DC_GetDCPtr( hdc );
441
442     TRACE("(%08x)\n",hdc);
443
444     if (!dc) return TRUE;
445
446     if (!dc->funcs->pSwapBuffers)
447     {
448         FIXME(" :stub\n");
449         bRet = TRUE;
450     }
451     else bRet = dc->funcs->pSwapBuffers(dc->physDev);
452
453     GDI_ReleaseObj( hdc );
454     return bRet;
455 }
456
457
458 /***********************************************************************
459  *           PaintRgn    (GDI32.@)
460  */
461 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
462 {
463     BOOL ret = FALSE;
464     DC * dc = DC_GetDCUpdate( hdc );
465     if (dc)
466     {
467         if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
468         GDI_ReleaseObj( hdc );
469     }
470     return ret;
471 }
472
473
474 /***********************************************************************
475  *           FillRgn    (GDI32.@)
476  */
477 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
478 {
479     BOOL retval = FALSE;
480     HBRUSH prevBrush;
481     DC * dc = DC_GetDCUpdate( hdc );
482
483     if (!dc) return FALSE;
484     if(dc->funcs->pFillRgn)
485         retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
486     else if ((prevBrush = SelectObject( hdc, hbrush )))
487     {
488     retval = PaintRgn( hdc, hrgn );
489     SelectObject( hdc, prevBrush );
490     }
491     GDI_ReleaseObj( hdc );
492     return retval;
493 }
494
495
496 /***********************************************************************
497  *           FrameRgn     (GDI32.@)
498  */
499 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
500                           INT nWidth, INT nHeight )
501 {
502     BOOL ret = FALSE;
503     DC *dc = DC_GetDCUpdate( hdc );
504
505     if (!dc) return FALSE;
506     if(dc->funcs->pFrameRgn)
507         ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
508     else
509     {
510         HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
511         if (tmp)
512         {
513             if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
514             {
515                 FillRgn( hdc, tmp, hbrush );
516                 ret = TRUE;
517             }
518             DeleteObject( tmp );
519         }
520     }
521     GDI_ReleaseObj( hdc );
522     return ret;
523 }
524
525
526 /***********************************************************************
527  *           InvertRgn    (GDI32.@)
528  */
529 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
530 {
531     HBRUSH prevBrush;
532     INT prevROP;
533     BOOL retval;
534     DC *dc = DC_GetDCUpdate( hdc );
535     if (!dc) return FALSE;
536
537     if(dc->funcs->pInvertRgn)
538         retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
539     else
540     {
541     prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
542     prevROP = SetROP2( hdc, R2_NOT );
543     retval = PaintRgn( hdc, hrgn );
544     SelectObject( hdc, prevBrush );
545     SetROP2( hdc, prevROP );
546     }
547     GDI_ReleaseObj( hdc );
548     return retval;
549 }
550
551
552 /**********************************************************************
553  *          Polyline   (GDI32.@)
554  */
555 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
556 {
557     BOOL ret = FALSE;
558     DC * dc = DC_GetDCUpdate( hdc );
559     if (dc)
560     {
561         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
562         else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
563         GDI_ReleaseObj( hdc );
564     }
565     return ret;
566 }
567
568 /**********************************************************************
569  *          PolylineTo   (GDI32.@)
570  */
571 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
572 {
573     DC * dc = DC_GetDCUpdate( hdc );
574     BOOL ret = FALSE;
575
576     if(!dc) return FALSE;
577
578     if(PATH_IsPathOpen(dc->path))
579         ret = PATH_PolylineTo(dc, pt, cCount);
580
581     else if(dc->funcs->pPolylineTo)
582         ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
583
584     else { /* do it using Polyline */
585         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
586                                 sizeof(POINT) * (cCount + 1) );
587         if (pts)
588         {
589         pts[0].x = dc->CursPosX;
590         pts[0].y = dc->CursPosY;
591         memcpy( pts + 1, pt, sizeof(POINT) * cCount );
592         ret = Polyline( hdc, pts, cCount + 1 );
593         HeapFree( GetProcessHeap(), 0, pts );
594     }
595     }
596     if(ret) {
597         dc->CursPosX = pt[cCount-1].x;
598         dc->CursPosY = pt[cCount-1].y;
599     }
600     GDI_ReleaseObj( hdc );
601     return ret;
602 }
603
604
605 /**********************************************************************
606  *          Polygon  (GDI32.@)
607  */
608 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
609 {
610     BOOL ret = FALSE;
611     DC * dc = DC_GetDCUpdate( hdc );
612     if (dc)
613     {
614         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
615         else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
616         GDI_ReleaseObj( hdc );
617     }
618     return ret;
619 }
620
621
622 /**********************************************************************
623  *          PolyPolygon  (GDI32.@)
624  */
625 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
626                              UINT polygons )
627 {
628     BOOL ret = FALSE;
629     DC * dc = DC_GetDCUpdate( hdc );
630     if (dc)
631     {
632         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
633         else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
634         GDI_ReleaseObj( hdc );
635     }
636     return ret;
637 }
638
639 /**********************************************************************
640  *          PolyPolyline  (GDI32.@)
641  */
642 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
643                             DWORD polylines )
644 {
645     BOOL ret = FALSE;
646     DC * dc = DC_GetDCUpdate( hdc );
647     if (dc)
648     {
649         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
650         else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
651         GDI_ReleaseObj( hdc );
652     }
653     return ret;
654 }
655
656 /**********************************************************************
657  *          ExtFloodFill   (GDI32.@)
658  */
659 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
660                               UINT fillType )
661 {
662     BOOL ret = FALSE;
663     DC * dc = DC_GetDCUpdate( hdc );
664     if (dc)
665     {
666         if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
667         GDI_ReleaseObj( hdc );
668     }
669     return ret;
670 }
671
672
673 /**********************************************************************
674  *          FloodFill   (GDI32.@)
675  */
676 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
677 {
678     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
679 }
680
681
682 /******************************************************************************
683  * PolyBezier [GDI32.@]
684  * Draws one or more Bezier curves
685  *
686  * PARAMS
687  *    hDc     [I] Handle to device context
688  *    lppt    [I] Pointer to endpoints and control points
689  *    cPoints [I] Count of endpoints and control points
690  *
691  * RETURNS STD
692  */
693 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
694 {
695     BOOL ret = FALSE;
696     DC * dc = DC_GetDCUpdate( hdc );
697
698     if(!dc) return FALSE;
699
700     if(PATH_IsPathOpen(dc->path))
701         ret = PATH_PolyBezier(dc, lppt, cPoints);
702     else if (dc->funcs->pPolyBezier)
703         ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
704     else  /* We'll convert it into line segments and draw them using Polyline */
705     {
706         POINT *Pts;
707         INT nOut;
708
709         if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
710         {
711             TRACE("Pts = %p, no = %d\n", Pts, nOut);
712             ret = Polyline( dc->hSelf, Pts, nOut );
713             HeapFree( GetProcessHeap(), 0, Pts );
714         }
715     }
716
717     GDI_ReleaseObj( hdc );
718     return ret;
719 }
720
721 /******************************************************************************
722  * PolyBezierTo [GDI32.@]
723  * Draws one or more Bezier curves
724  *
725  * PARAMS
726  *    hDc     [I] Handle to device context
727  *    lppt    [I] Pointer to endpoints and control points
728  *    cPoints [I] Count of endpoints and control points
729  *
730  * RETURNS STD
731  */
732 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
733 {
734     DC * dc = DC_GetDCUpdate( hdc );
735     BOOL ret;
736
737     if(!dc) return FALSE;
738
739     if(PATH_IsPathOpen(dc->path))
740         ret = PATH_PolyBezierTo(dc, lppt, cPoints);
741     else if(dc->funcs->pPolyBezierTo)
742         ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
743     else { /* We'll do it using PolyBezier */
744         POINT *pt;
745         pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
746         if(!pt) return FALSE;
747         pt[0].x = dc->CursPosX;
748         pt[0].y = dc->CursPosY;
749         memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
750         ret = PolyBezier(dc->hSelf, pt, cPoints+1);
751         HeapFree( GetProcessHeap(), 0, pt );
752     }
753     if(ret) {
754         dc->CursPosX = lppt[cPoints-1].x;
755         dc->CursPosY = lppt[cPoints-1].y;
756     }
757     GDI_ReleaseObj( hdc );
758     return ret;
759 }
760
761 /***********************************************************************
762  *      AngleArc (GDI32.@)
763  */
764 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
765 {
766     INT x1,y1,x2,y2, arcdir;
767     BOOL result;
768     DC *dc;
769
770     if( (signed int)dwRadius < 0 )
771         return FALSE;
772
773     dc = DC_GetDCUpdate( hdc );
774     if(!dc) return FALSE;
775
776     if(dc->funcs->pAngleArc)
777     {
778         result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
779
780         GDI_ReleaseObj( hdc );
781         return result;
782     }
783     GDI_ReleaseObj( hdc );
784
785     /* AngleArc always works counterclockwise */
786     arcdir = GetArcDirection( hdc );
787     SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
788
789     x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
790     y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
791     x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
792     y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
793
794     LineTo( hdc, x1, y1 );
795     if( eSweepAngle >= 0 )
796         result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
797                       x1, y1, x2, y2 );
798     else
799         result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
800                       x2, y2, x1, y1 );
801
802     if( result ) MoveToEx( hdc, x2, y2, NULL );
803     SetArcDirection( hdc, arcdir );
804     return result;
805 }
806
807 /***********************************************************************
808  *      PolyDraw (GDI32.@)
809  */
810 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
811                        DWORD cCount)
812 {
813     DC *dc;
814     BOOL result;
815     POINT lastmove;
816     int i;
817
818     dc = DC_GetDCUpdate( hdc );
819     if(!dc) return FALSE;
820
821     if(dc->funcs->pPolyDraw)
822     {
823         result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
824         GDI_ReleaseObj( hdc );
825         return result;
826     }
827     GDI_ReleaseObj( hdc );
828
829     /* check for each bezierto if there are two more points */
830     for( i = 0; i < cCount; i++ )
831         if( lpbTypes[i] != PT_MOVETO &&
832             lpbTypes[i] & PT_BEZIERTO )
833         {
834             if( cCount < i+3 )
835                 return FALSE;
836             else
837                 i += 2;
838         }
839
840     /* if no moveto occurs, we will close the figure here */
841     lastmove.x = dc->CursPosX;
842     lastmove.y = dc->CursPosY;
843
844     /* now let's draw */
845     for( i = 0; i < cCount; i++ )
846     {
847         if( lpbTypes[i] == PT_MOVETO )
848         {
849             MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
850             lastmove.x = dc->CursPosX;
851             lastmove.y = dc->CursPosY;
852         }
853         else if( lpbTypes[i] & PT_LINETO )
854             LineTo( hdc, lppt[i].x, lppt[i].y );
855         else if( lpbTypes[i] & PT_BEZIERTO )
856         {
857             PolyBezierTo( hdc, &lppt[i], 3 );
858             i += 2;
859         }
860         else
861             return FALSE;
862
863         if( lpbTypes[i] & PT_CLOSEFIGURE )
864         {
865             if( PATH_IsPathOpen( dc->path ) )
866                 CloseFigure( hdc );
867             else
868                 LineTo( hdc, lastmove.x, lastmove.y );
869         }
870     }
871
872     return TRUE;
873 }
874
875 /******************************************************************
876  *
877  *   *Very* simple bezier drawing code,
878  *
879  *   It uses a recursive algorithm to divide the curve in a series
880  *   of straight line segements. Not ideal but for me sufficient.
881  *   If you are in need for something better look for some incremental
882  *   algorithm.
883  *
884  *   7 July 1998 Rein Klazes
885  */
886
887  /*
888   * some macro definitions for bezier drawing
889   *
890   * to avoid trucation errors the coordinates are
891   * shifted upwards. When used in drawing they are
892   * shifted down again, including correct rounding
893   * and avoiding floating point arithmatic
894   * 4 bits should allow 27 bits coordinates which I saw
895   * somewere in the win32 doc's
896   *
897   */
898
899 #define BEZIERSHIFTBITS 4
900 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
901 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
902 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
903 /* maximum depth of recursion */
904 #define BEZIERMAXDEPTH  8
905
906 /* size of array to store points on */
907 /* enough for one curve */
908 #define BEZIER_INITBUFSIZE    (150)
909
910 /* calculate Bezier average, in this case the middle
911  * correctly rounded...
912  * */
913
914 #define BEZIERMIDDLE(Mid, P1, P2) \
915     (Mid).x=((P1).x+(P2).x + 1)/2;\
916     (Mid).y=((P1).y+(P2).y + 1)/2;
917
918 /**********************************************************
919 * BezierCheck helper function to check
920 * that recursion can be terminated
921 *       Points[0] and Points[3] are begin and endpoint
922 *       Points[1] and Points[2] are control points
923 *       level is the recursion depth
924 *       returns true if the recusion can be terminated
925 */
926 static BOOL BezierCheck( int level, POINT *Points)
927 {
928     INT dx, dy;
929     dx=Points[3].x-Points[0].x;
930     dy=Points[3].y-Points[0].y;
931     if(abs(dy)<=abs(dx)){/* shallow line */
932         /* check that control points are between begin and end */
933         if(Points[1].x < Points[0].x){
934             if(Points[1].x < Points[3].x)
935                 return FALSE;
936         }else
937             if(Points[1].x > Points[3].x)
938                 return FALSE;
939         if(Points[2].x < Points[0].x){
940             if(Points[2].x < Points[3].x)
941                 return FALSE;
942         }else
943             if(Points[2].x > Points[3].x)
944                 return FALSE;
945         dx=BEZIERSHIFTDOWN(dx);
946         if(!dx) return TRUE;
947         if(abs(Points[1].y-Points[0].y-(dy/dx)*
948                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
949            abs(Points[2].y-Points[0].y-(dy/dx)*
950                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
951             return FALSE;
952         else
953             return TRUE;
954     }else{ /* steep line */
955         /* check that control points are between begin and end */
956         if(Points[1].y < Points[0].y){
957             if(Points[1].y < Points[3].y)
958                 return FALSE;
959         }else
960             if(Points[1].y > Points[3].y)
961                 return FALSE;
962         if(Points[2].y < Points[0].y){
963             if(Points[2].y < Points[3].y)
964                 return FALSE;
965         }else
966             if(Points[2].y > Points[3].y)
967                 return FALSE;
968         dy=BEZIERSHIFTDOWN(dy);
969         if(!dy) return TRUE;
970         if(abs(Points[1].x-Points[0].x-(dx/dy)*
971                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
972            abs(Points[2].x-Points[0].x-(dx/dy)*
973                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
974             return FALSE;
975         else
976             return TRUE;
977     }
978 }
979
980 /* Helper for GDI_Bezier.
981  * Just handles one Bezier, so Points should point to four POINTs
982  */
983 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
984                                 INT *nPtsOut, INT level )
985 {
986     if(*nPtsOut == *dwOut) {
987         *dwOut *= 2;
988         *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
989                                *dwOut * sizeof(POINT) );
990     }
991
992     if(!level || BezierCheck(level, Points)) {
993         if(*nPtsOut == 0) {
994             (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
995             (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
996             *nPtsOut = 1;
997         }
998         (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
999         (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1000         (*nPtsOut) ++;
1001     } else {
1002         POINT Points2[4]; /* for the second recursive call */
1003         Points2[3]=Points[3];
1004         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1005         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1006         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1007
1008         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1009         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1010         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1011
1012         Points2[0]=Points[3];
1013
1014         /* do the two halves */
1015         GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1016         GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1017     }
1018 }
1019
1020
1021
1022 /***********************************************************************
1023  *           GDI_Bezier   [INTERNAL]
1024  *   Calculate line segments that approximate -what microsoft calls- a bezier
1025  *   curve.
1026  *   The routine recursively divides the curve in two parts until a straight
1027  *   line can be drawn
1028  *
1029  *  PARAMS
1030  *
1031  *  Points  [I] Ptr to count POINTs which are the end and control points
1032  *              of the set of Bezier curves to flatten.
1033  *  count   [I] Number of Points.  Must be 3n+1.
1034  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1035  *              lines+1).
1036  *
1037  *  RETURNS
1038  *
1039  *  Ptr to an array of POINTs that contain the lines that approximinate the
1040  *  Beziers.  The array is allocated on the process heap and it is the caller's
1041  *  responsibility to HeapFree it. [this is not a particularly nice interface
1042  *  but since we can't know in advance how many points will generate, the
1043  *  alternative would be to call the function twice, once to determine the size
1044  *  and a second time to do the work - I decided this was too much of a pain].
1045  */
1046 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1047 {
1048     POINT *out;
1049     INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1050
1051     if((count - 1) % 3 != 0) {
1052         ERR("Invalid no. of points\n");
1053         return NULL;
1054     }
1055     *nPtsOut = 0;
1056     out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1057     for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1058         POINT ptBuf[4];
1059         memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1060         for(i = 0; i < 4; i++) {
1061             ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1062             ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1063         }
1064         GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1065     }
1066     TRACE("Produced %d points\n", *nPtsOut);
1067     return out;
1068 }