Various trace fixes.
[wine] / dlls / gdi / 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 <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "gdi.h"
35 #include "gdi_private.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
39
40
41 /***********************************************************************
42  *           LineTo    (GDI32.@)
43  */
44 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
45 {
46     DC * dc = DC_GetDCUpdate( hdc );
47     BOOL ret;
48
49     if(!dc) return FALSE;
50
51     if(PATH_IsPathOpen(dc->path))
52         ret = PATH_LineTo(dc, x, y);
53     else
54         ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
55     if(ret) {
56         dc->CursPosX = x;
57         dc->CursPosY = y;
58     }
59     GDI_ReleaseObj( hdc );
60     return ret;
61 }
62
63
64 /***********************************************************************
65  *           MoveToEx    (GDI32.@)
66  */
67 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
68 {
69     BOOL ret = TRUE;
70     DC * dc = DC_GetDCPtr( hdc );
71
72     if(!dc) return FALSE;
73
74     if(pt) {
75         pt->x = dc->CursPosX;
76         pt->y = dc->CursPosY;
77     }
78     dc->CursPosX = x;
79     dc->CursPosY = y;
80
81     if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
82     else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
83     GDI_ReleaseObj( hdc );
84     return ret;
85 }
86
87
88 /***********************************************************************
89  *           Arc    (GDI32.@)
90  */
91 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
92                      INT bottom, INT xstart, INT ystart,
93                      INT xend, INT yend )
94 {
95     BOOL ret = FALSE;
96     DC * dc = DC_GetDCUpdate( hdc );
97     if (dc)
98     {
99     if(PATH_IsPathOpen(dc->path))
100             ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
101         else if (dc->funcs->pArc)
102             ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
103         GDI_ReleaseObj( hdc );
104     }
105     return ret;
106 }
107
108 /***********************************************************************
109  *           ArcTo    (GDI32.@)
110  */
111 BOOL WINAPI ArcTo( HDC hdc,
112                      INT left,   INT top,
113                      INT right,  INT bottom,
114                      INT xstart, INT ystart,
115                      INT xend,   INT yend )
116 {
117     BOOL result;
118     DC * dc = DC_GetDCUpdate( hdc );
119     if(!dc) return FALSE;
120
121     if(dc->funcs->pArcTo)
122     {
123         result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
124                                   xstart, ystart, xend, yend );
125         GDI_ReleaseObj( hdc );
126         return result;
127     }
128     GDI_ReleaseObj( hdc );
129     /*
130      * Else emulate it.
131      * According to the documentation, a line is drawn from the current
132      * position to the starting point of the arc.
133      */
134     LineTo(hdc, xstart, ystart);
135     /*
136      * Then the arc is drawn.
137      */
138     result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
139     /*
140      * If no error occurred, the current position is moved to the ending
141      * point of the arc.
142      */
143     if (result) MoveToEx(hdc, xend, yend, NULL);
144     return result;
145 }
146
147
148 /***********************************************************************
149  *           Pie   (GDI32.@)
150  */
151 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
152                      INT right, INT bottom, INT xstart, INT ystart,
153                      INT xend, INT yend )
154 {
155     BOOL ret = FALSE;
156     DC * dc = DC_GetDCUpdate( hdc );
157     if (!dc) return FALSE;
158
159     if(PATH_IsPathOpen(dc->path))
160         ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
161     else if(dc->funcs->pPie)
162         ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
163
164     GDI_ReleaseObj( hdc );
165     return ret;
166 }
167
168
169 /***********************************************************************
170  *           Chord    (GDI32.@)
171  */
172 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
173                        INT right, INT bottom, INT xstart, INT ystart,
174                        INT xend, INT yend )
175 {
176     BOOL ret = FALSE;
177     DC * dc = DC_GetDCUpdate( hdc );
178     if (!dc) return FALSE;
179
180     if(PATH_IsPathOpen(dc->path))
181         ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
182     else if(dc->funcs->pChord)
183         ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
184
185     GDI_ReleaseObj( hdc );
186     return ret;
187 }
188
189
190 /***********************************************************************
191  *           Ellipse    (GDI32.@)
192  */
193 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
194                          INT right, INT bottom )
195 {
196     BOOL ret = FALSE;
197     DC * dc = DC_GetDCUpdate( hdc );
198     if (!dc) return FALSE;
199
200     if(PATH_IsPathOpen(dc->path))
201         ret = PATH_Ellipse(dc,left,top,right,bottom);
202     else if (dc->funcs->pEllipse)
203         ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
204
205     GDI_ReleaseObj( hdc );
206     return ret;
207 }
208
209
210 /***********************************************************************
211  *           Rectangle    (GDI32.@)
212  */
213 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
214                            INT right, INT bottom )
215 {
216     BOOL ret = FALSE;
217     DC * dc = DC_GetDCUpdate( hdc );
218     if (dc)
219     {
220     if(PATH_IsPathOpen(dc->path))
221             ret = PATH_Rectangle(dc, left, top, right, bottom);
222         else if (dc->funcs->pRectangle)
223             ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
224         GDI_ReleaseObj( hdc );
225     }
226     return ret;
227 }
228
229
230 /***********************************************************************
231  *           RoundRect    (GDI32.@)
232  */
233 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
234                            INT bottom, INT ell_width, INT ell_height )
235 {
236     BOOL ret = FALSE;
237     DC *dc = DC_GetDCUpdate( hdc );
238
239     if (dc)
240     {
241         if(PATH_IsPathOpen(dc->path))
242             ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
243         else if (dc->funcs->pRoundRect)
244             ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
245         GDI_ReleaseObj( hdc );
246     }
247     return ret;
248 }
249
250 /***********************************************************************
251  *           SetPixel    (GDI32.@)
252  */
253 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
254 {
255     COLORREF ret = 0;
256     DC * dc = DC_GetDCUpdate( hdc );
257     if (dc)
258     {
259         if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
260         GDI_ReleaseObj( hdc );
261     }
262     return ret;
263 }
264
265 /***********************************************************************
266  *           SetPixelV    (GDI32.@)
267  */
268 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
269 {
270     BOOL ret = FALSE;
271     DC * dc = DC_GetDCUpdate( hdc );
272     if (dc)
273     {
274         if (dc->funcs->pSetPixel)
275         {
276             dc->funcs->pSetPixel(dc->physDev,x,y,color);
277             ret = TRUE;
278         }
279         GDI_ReleaseObj( hdc );
280     }
281     return ret;
282 }
283
284 /***********************************************************************
285  *           GetPixel    (GDI32.@)
286  */
287 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
288 {
289     COLORREF ret = CLR_INVALID;
290     DC * dc = DC_GetDCUpdate( hdc );
291
292     if (dc)
293     {
294     /* FIXME: should this be in the graphics driver? */
295         if (PtVisible( hdc, x, y ))
296         {
297             if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
298         }
299         GDI_ReleaseObj( hdc );
300     }
301     return ret;
302 }
303
304
305 /******************************************************************************
306  * ChoosePixelFormat [GDI32.@]
307  * Matches a pixel format to given format
308  *
309  * PARAMS
310  *    hdc  [I] Device context to search for best pixel match
311  *    ppfd [I] Pixel format for which a match is sought
312  *
313  * RETURNS
314  *    Success: Pixel format index closest to given format
315  *    Failure: 0
316  */
317 INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
318 {
319     INT ret = 0;
320     DC * dc = DC_GetDCPtr( hdc );
321
322     TRACE("(%p,%p)\n",hdc,ppfd);
323
324     if (!dc) return 0;
325
326     if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
327     else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
328
329     GDI_ReleaseObj( hdc );
330     return ret;
331 }
332
333
334 /******************************************************************************
335  * SetPixelFormat [GDI32.@]
336  * Sets pixel format of device context
337  *
338  * PARAMS
339  *    hdc          [I] Device context to search for best pixel match
340  *    iPixelFormat [I] Pixel format index
341  *    ppfd         [I] Pixel format for which a match is sought
342  *
343  * RETURNS
344  *    Success: TRUE
345  *    Failure: FALSE
346  */
347 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
348                             const PIXELFORMATDESCRIPTOR *ppfd)
349 {
350     INT bRet = FALSE;
351     DC * dc = DC_GetDCPtr( hdc );
352
353     TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
354
355     if (!dc) return 0;
356
357     if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
358     else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
359
360     GDI_ReleaseObj( hdc );
361     return bRet;
362 }
363
364
365 /******************************************************************************
366  * GetPixelFormat [GDI32.@]
367  * Gets index of pixel format of DC
368  *
369  * PARAMETERS
370  *    hdc [I] Device context whose pixel format index is sought
371  *
372  * RETURNS
373  *    Success: Currently selected pixel format
374  *    Failure: 0
375  */
376 INT WINAPI GetPixelFormat( HDC hdc )
377 {
378     INT ret = 0;
379     DC * dc = DC_GetDCPtr( hdc );
380
381     TRACE("(%p)\n",hdc);
382
383     if (!dc) return 0;
384
385     if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
386     else ret = dc->funcs->pGetPixelFormat(dc->physDev);
387
388     GDI_ReleaseObj( hdc );
389     return ret;
390 }
391
392
393 /******************************************************************************
394  * DescribePixelFormat [GDI32.@]
395  * Gets info about pixel format from DC
396  *
397  * PARAMS
398  *    hdc          [I] Device context
399  *    iPixelFormat [I] Pixel format selector
400  *    nBytes       [I] Size of buffer
401  *    ppfd         [O] Pointer to structure to receive pixel format data
402  *
403  * RETURNS
404  *    Success: Maximum pixel format index of the device context
405  *    Failure: 0
406  */
407 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
408                                 LPPIXELFORMATDESCRIPTOR ppfd )
409 {
410     INT ret = 0;
411     DC * dc = DC_GetDCPtr( hdc );
412
413     TRACE("(%p,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
414
415     if (!dc) return 0;
416
417     if (!dc->funcs->pDescribePixelFormat)
418     {
419         FIXME(" :stub\n");
420         ppfd->nSize = nBytes;
421         ppfd->nVersion = 1;
422         ret = 3;
423     }
424     else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
425
426     GDI_ReleaseObj( hdc );
427     return ret;
428 }
429
430
431 /******************************************************************************
432  * SwapBuffers [GDI32.@]
433  * Exchanges front and back buffers of window
434  *
435  * PARAMS
436  *    hdc [I] Device context whose buffers get swapped
437  *
438  * RETURNS
439  *    Success: TRUE
440  *    Failure: FALSE
441  */
442 BOOL WINAPI SwapBuffers( HDC hdc )
443 {
444     INT bRet = FALSE;
445     DC * dc = DC_GetDCPtr( hdc );
446
447     TRACE("(%p)\n",hdc);
448
449     if (!dc) return TRUE;
450
451     if (!dc->funcs->pSwapBuffers)
452     {
453         FIXME(" :stub\n");
454         bRet = TRUE;
455     }
456     else bRet = dc->funcs->pSwapBuffers(dc->physDev);
457
458     GDI_ReleaseObj( hdc );
459     return bRet;
460 }
461
462
463 /***********************************************************************
464  *           PaintRgn    (GDI32.@)
465  */
466 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
467 {
468     BOOL ret = FALSE;
469     DC * dc = DC_GetDCUpdate( hdc );
470     if (dc)
471     {
472         if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
473         GDI_ReleaseObj( hdc );
474     }
475     return ret;
476 }
477
478
479 /***********************************************************************
480  *           FillRgn    (GDI32.@)
481  */
482 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
483 {
484     BOOL retval = FALSE;
485     HBRUSH prevBrush;
486     DC * dc = DC_GetDCUpdate( hdc );
487
488     if (!dc) return FALSE;
489     if(dc->funcs->pFillRgn)
490         retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
491     else if ((prevBrush = SelectObject( hdc, hbrush )))
492     {
493     retval = PaintRgn( hdc, hrgn );
494     SelectObject( hdc, prevBrush );
495     }
496     GDI_ReleaseObj( hdc );
497     return retval;
498 }
499
500
501 /***********************************************************************
502  *           FrameRgn     (GDI32.@)
503  */
504 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
505                           INT nWidth, INT nHeight )
506 {
507     BOOL ret = FALSE;
508     DC *dc = DC_GetDCUpdate( hdc );
509
510     if (!dc) return FALSE;
511     if(dc->funcs->pFrameRgn)
512         ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
513     else
514     {
515         HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
516         if (tmp)
517         {
518             if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
519             {
520                 FillRgn( hdc, tmp, hbrush );
521                 ret = TRUE;
522             }
523             DeleteObject( tmp );
524         }
525     }
526     GDI_ReleaseObj( hdc );
527     return ret;
528 }
529
530
531 /***********************************************************************
532  *           InvertRgn    (GDI32.@)
533  */
534 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
535 {
536     HBRUSH prevBrush;
537     INT prevROP;
538     BOOL retval;
539     DC *dc = DC_GetDCUpdate( hdc );
540     if (!dc) return FALSE;
541
542     if(dc->funcs->pInvertRgn)
543         retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
544     else
545     {
546     prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
547     prevROP = SetROP2( hdc, R2_NOT );
548     retval = PaintRgn( hdc, hrgn );
549     SelectObject( hdc, prevBrush );
550     SetROP2( hdc, prevROP );
551     }
552     GDI_ReleaseObj( hdc );
553     return retval;
554 }
555
556
557 /**********************************************************************
558  *          Polyline   (GDI32.@)
559  */
560 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
561 {
562     BOOL ret = FALSE;
563     DC * dc = DC_GetDCUpdate( hdc );
564     if (dc)
565     {
566         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
567         else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
568         GDI_ReleaseObj( hdc );
569     }
570     return ret;
571 }
572
573 /**********************************************************************
574  *          PolylineTo   (GDI32.@)
575  */
576 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
577 {
578     DC * dc = DC_GetDCUpdate( hdc );
579     BOOL ret = FALSE;
580
581     if(!dc) return FALSE;
582
583     if(PATH_IsPathOpen(dc->path))
584         ret = PATH_PolylineTo(dc, pt, cCount);
585
586     else if(dc->funcs->pPolylineTo)
587         ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
588
589     else { /* do it using Polyline */
590         POINT *pts = HeapAlloc( GetProcessHeap(), 0,
591                                 sizeof(POINT) * (cCount + 1) );
592         if (pts)
593         {
594         pts[0].x = dc->CursPosX;
595         pts[0].y = dc->CursPosY;
596         memcpy( pts + 1, pt, sizeof(POINT) * cCount );
597         ret = Polyline( hdc, pts, cCount + 1 );
598         HeapFree( GetProcessHeap(), 0, pts );
599     }
600     }
601     if(ret) {
602         dc->CursPosX = pt[cCount-1].x;
603         dc->CursPosY = pt[cCount-1].y;
604     }
605     GDI_ReleaseObj( hdc );
606     return ret;
607 }
608
609
610 /**********************************************************************
611  *          Polygon  (GDI32.@)
612  */
613 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
614 {
615     BOOL ret = FALSE;
616     DC * dc = DC_GetDCUpdate( hdc );
617     if (dc)
618     {
619         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
620         else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
621         GDI_ReleaseObj( hdc );
622     }
623     return ret;
624 }
625
626
627 /**********************************************************************
628  *          PolyPolygon  (GDI32.@)
629  */
630 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
631                              UINT polygons )
632 {
633     BOOL ret = FALSE;
634     DC * dc = DC_GetDCUpdate( hdc );
635     if (dc)
636     {
637         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
638         else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
639         GDI_ReleaseObj( hdc );
640     }
641     return ret;
642 }
643
644 /**********************************************************************
645  *          PolyPolyline  (GDI32.@)
646  */
647 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
648                             DWORD polylines )
649 {
650     BOOL ret = FALSE;
651     DC * dc = DC_GetDCUpdate( hdc );
652     if (dc)
653     {
654         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
655         else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
656         GDI_ReleaseObj( hdc );
657     }
658     return ret;
659 }
660
661 /**********************************************************************
662  *          ExtFloodFill   (GDI32.@)
663  */
664 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
665                               UINT fillType )
666 {
667     BOOL ret = FALSE;
668     DC * dc = DC_GetDCUpdate( hdc );
669     if (dc)
670     {
671         if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
672         GDI_ReleaseObj( hdc );
673     }
674     return ret;
675 }
676
677
678 /**********************************************************************
679  *          FloodFill   (GDI32.@)
680  */
681 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
682 {
683     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
684 }
685
686
687 /******************************************************************************
688  * PolyBezier [GDI32.@]
689  * Draws one or more Bezier curves
690  *
691  * PARAMS
692  *    hDc     [I] Handle to device context
693  *    lppt    [I] Pointer to endpoints and control points
694  *    cPoints [I] Count of endpoints and control points
695  *
696  * RETURNS
697  *    Success: TRUE
698  *    Failure: FALSE
699  */
700 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
701 {
702     BOOL ret = FALSE;
703     DC * dc;
704
705     /* cPoints must be 3 * n + 1 (where n>=1) */
706     if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
707
708     dc = DC_GetDCUpdate( hdc );
709     if(!dc) return FALSE;
710
711     if(PATH_IsPathOpen(dc->path))
712         ret = PATH_PolyBezier(dc, lppt, cPoints);
713     else if (dc->funcs->pPolyBezier)
714         ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
715     else  /* We'll convert it into line segments and draw them using Polyline */
716     {
717         POINT *Pts;
718         INT nOut;
719
720         if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
721         {
722             TRACE("Pts = %p, no = %d\n", Pts, nOut);
723             ret = Polyline( dc->hSelf, Pts, nOut );
724             HeapFree( GetProcessHeap(), 0, Pts );
725         }
726     }
727
728     GDI_ReleaseObj( hdc );
729     return ret;
730 }
731
732 /******************************************************************************
733  * PolyBezierTo [GDI32.@]
734  * Draws one or more Bezier curves
735  *
736  * PARAMS
737  *    hDc     [I] Handle to device context
738  *    lppt    [I] Pointer to endpoints and control points
739  *    cPoints [I] Count of endpoints and control points
740  *
741  * RETURNS
742  *    Success: TRUE
743  *    Failure: FALSE
744  */
745 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
746 {
747     DC * dc;
748     BOOL ret;
749
750     /* cbPoints must be 3 * n (where n>=1) */
751     if (!cPoints || (cPoints % 3) != 0) return FALSE;
752
753     dc = DC_GetDCUpdate( hdc );
754     if(!dc) return FALSE;
755
756     if(PATH_IsPathOpen(dc->path))
757         ret = PATH_PolyBezierTo(dc, lppt, cPoints);
758     else if(dc->funcs->pPolyBezierTo)
759         ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
760     else { /* We'll do it using PolyBezier */
761         POINT *pt;
762         pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
763         if(!pt) return FALSE;
764         pt[0].x = dc->CursPosX;
765         pt[0].y = dc->CursPosY;
766         memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
767         ret = PolyBezier(dc->hSelf, pt, cPoints+1);
768         HeapFree( GetProcessHeap(), 0, pt );
769     }
770     if(ret) {
771         dc->CursPosX = lppt[cPoints-1].x;
772         dc->CursPosY = lppt[cPoints-1].y;
773     }
774     GDI_ReleaseObj( hdc );
775     return ret;
776 }
777
778 /***********************************************************************
779  *      AngleArc (GDI32.@)
780  */
781 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
782 {
783     INT x1,y1,x2,y2, arcdir;
784     BOOL result;
785     DC *dc;
786
787     if( (signed int)dwRadius < 0 )
788         return FALSE;
789
790     dc = DC_GetDCUpdate( hdc );
791     if(!dc) return FALSE;
792
793     if(dc->funcs->pAngleArc)
794     {
795         result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
796
797         GDI_ReleaseObj( hdc );
798         return result;
799     }
800     GDI_ReleaseObj( hdc );
801
802     /* AngleArc always works counterclockwise */
803     arcdir = GetArcDirection( hdc );
804     SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
805
806     x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
807     y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
808     x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
809     y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
810
811     LineTo( hdc, x1, y1 );
812     if( eSweepAngle >= 0 )
813         result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
814                       x1, y1, x2, y2 );
815     else
816         result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
817                       x2, y2, x1, y1 );
818
819     if( result ) MoveToEx( hdc, x2, y2, NULL );
820     SetArcDirection( hdc, arcdir );
821     return result;
822 }
823
824 /***********************************************************************
825  *      PolyDraw (GDI32.@)
826  */
827 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
828                        DWORD cCount)
829 {
830     DC *dc;
831     BOOL result;
832     POINT lastmove;
833     unsigned int i;
834
835     dc = DC_GetDCUpdate( hdc );
836     if(!dc) return FALSE;
837
838     if(dc->funcs->pPolyDraw)
839     {
840         result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
841         GDI_ReleaseObj( hdc );
842         return result;
843     }
844     GDI_ReleaseObj( hdc );
845
846     /* check for each bezierto if there are two more points */
847     for( i = 0; i < cCount; i++ )
848         if( lpbTypes[i] != PT_MOVETO &&
849             lpbTypes[i] & PT_BEZIERTO )
850         {
851             if( cCount < i+3 )
852                 return FALSE;
853             else
854                 i += 2;
855         }
856
857     /* if no moveto occurs, we will close the figure here */
858     lastmove.x = dc->CursPosX;
859     lastmove.y = dc->CursPosY;
860
861     /* now let's draw */
862     for( i = 0; i < cCount; i++ )
863     {
864         if( lpbTypes[i] == PT_MOVETO )
865         {
866             MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
867             lastmove.x = dc->CursPosX;
868             lastmove.y = dc->CursPosY;
869         }
870         else if( lpbTypes[i] & PT_LINETO )
871             LineTo( hdc, lppt[i].x, lppt[i].y );
872         else if( lpbTypes[i] & PT_BEZIERTO )
873         {
874             PolyBezierTo( hdc, &lppt[i], 3 );
875             i += 2;
876         }
877         else
878             return FALSE;
879
880         if( lpbTypes[i] & PT_CLOSEFIGURE )
881         {
882             if( PATH_IsPathOpen( dc->path ) )
883                 CloseFigure( hdc );
884             else
885                 LineTo( hdc, lastmove.x, lastmove.y );
886         }
887     }
888
889     return TRUE;
890 }
891
892
893 /**********************************************************************
894  *           LineDDA   (GDI32.@)
895  */
896 BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
897                     LINEDDAPROC callback, LPARAM lParam )
898 {
899     INT xadd = 1, yadd = 1;
900     INT err,erradd;
901     INT cnt;
902     INT dx = nXEnd - nXStart;
903     INT dy = nYEnd - nYStart;
904
905     if (dx < 0)
906     {
907         dx = -dx;
908         xadd = -1;
909     }
910     if (dy < 0)
911     {
912         dy = -dy;
913         yadd = -1;
914     }
915     if (dx > dy)  /* line is "more horizontal" */
916     {
917         err = 2*dy - dx; erradd = 2*dy - 2*dx;
918         for(cnt = 0;cnt <= dx; cnt++)
919         {
920             callback(nXStart,nYStart,lParam);
921             if (err > 0)
922             {
923                 nYStart += yadd;
924                 err += erradd;
925             }
926             else err += 2*dy;
927             nXStart += xadd;
928         }
929     }
930     else   /* line is "more vertical" */
931     {
932         err = 2*dx - dy; erradd = 2*dx - 2*dy;
933         for(cnt = 0;cnt <= dy; cnt++)
934         {
935             callback(nXStart,nYStart,lParam);
936             if (err > 0)
937             {
938                 nXStart += xadd;
939                 err += erradd;
940             }
941             else err += 2*dx;
942             nYStart += yadd;
943         }
944     }
945     return TRUE;
946 }
947
948
949 /******************************************************************
950  *
951  *   *Very* simple bezier drawing code,
952  *
953  *   It uses a recursive algorithm to divide the curve in a series
954  *   of straight line segements. Not ideal but for me sufficient.
955  *   If you are in need for something better look for some incremental
956  *   algorithm.
957  *
958  *   7 July 1998 Rein Klazes
959  */
960
961  /*
962   * some macro definitions for bezier drawing
963   *
964   * to avoid truncation errors the coordinates are
965   * shifted upwards. When used in drawing they are
966   * shifted down again, including correct rounding
967   * and avoiding floating point arithmetic
968   * 4 bits should allow 27 bits coordinates which I saw
969   * somewhere in the win32 doc's
970   *
971   */
972
973 #define BEZIERSHIFTBITS 4
974 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
975 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
976 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
977 /* maximum depth of recursion */
978 #define BEZIERMAXDEPTH  8
979
980 /* size of array to store points on */
981 /* enough for one curve */
982 #define BEZIER_INITBUFSIZE    (150)
983
984 /* calculate Bezier average, in this case the middle
985  * correctly rounded...
986  * */
987
988 #define BEZIERMIDDLE(Mid, P1, P2) \
989     (Mid).x=((P1).x+(P2).x + 1)/2;\
990     (Mid).y=((P1).y+(P2).y + 1)/2;
991
992 /**********************************************************
993 * BezierCheck helper function to check
994 * that recursion can be terminated
995 *       Points[0] and Points[3] are begin and endpoint
996 *       Points[1] and Points[2] are control points
997 *       level is the recursion depth
998 *       returns true if the recusion can be terminated
999 */
1000 static BOOL BezierCheck( int level, POINT *Points)
1001 {
1002     INT dx, dy;
1003     dx=Points[3].x-Points[0].x;
1004     dy=Points[3].y-Points[0].y;
1005     if(abs(dy)<=abs(dx)){/* shallow line */
1006         /* check that control points are between begin and end */
1007         if(Points[1].x < Points[0].x){
1008             if(Points[1].x < Points[3].x)
1009                 return FALSE;
1010         }else
1011             if(Points[1].x > Points[3].x)
1012                 return FALSE;
1013         if(Points[2].x < Points[0].x){
1014             if(Points[2].x < Points[3].x)
1015                 return FALSE;
1016         }else
1017             if(Points[2].x > Points[3].x)
1018                 return FALSE;
1019         dx=BEZIERSHIFTDOWN(dx);
1020         if(!dx) return TRUE;
1021         if(abs(Points[1].y-Points[0].y-(dy/dx)*
1022                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1023            abs(Points[2].y-Points[0].y-(dy/dx)*
1024                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1025             return FALSE;
1026         else
1027             return TRUE;
1028     }else{ /* steep line */
1029         /* check that control points are between begin and end */
1030         if(Points[1].y < Points[0].y){
1031             if(Points[1].y < Points[3].y)
1032                 return FALSE;
1033         }else
1034             if(Points[1].y > Points[3].y)
1035                 return FALSE;
1036         if(Points[2].y < Points[0].y){
1037             if(Points[2].y < Points[3].y)
1038                 return FALSE;
1039         }else
1040             if(Points[2].y > Points[3].y)
1041                 return FALSE;
1042         dy=BEZIERSHIFTDOWN(dy);
1043         if(!dy) return TRUE;
1044         if(abs(Points[1].x-Points[0].x-(dx/dy)*
1045                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1046            abs(Points[2].x-Points[0].x-(dx/dy)*
1047                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1048             return FALSE;
1049         else
1050             return TRUE;
1051     }
1052 }
1053
1054 /* Helper for GDI_Bezier.
1055  * Just handles one Bezier, so Points should point to four POINTs
1056  */
1057 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1058                                 INT *nPtsOut, INT level )
1059 {
1060     if(*nPtsOut == *dwOut) {
1061         *dwOut *= 2;
1062         *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1063                                *dwOut * sizeof(POINT) );
1064     }
1065
1066     if(!level || BezierCheck(level, Points)) {
1067         if(*nPtsOut == 0) {
1068             (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1069             (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1070             *nPtsOut = 1;
1071         }
1072         (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1073         (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1074         (*nPtsOut) ++;
1075     } else {
1076         POINT Points2[4]; /* for the second recursive call */
1077         Points2[3]=Points[3];
1078         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1079         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1080         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1081
1082         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1083         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1084         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1085
1086         Points2[0]=Points[3];
1087
1088         /* do the two halves */
1089         GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1090         GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1091     }
1092 }
1093
1094
1095
1096 /***********************************************************************
1097  *           GDI_Bezier   [INTERNAL]
1098  *   Calculate line segments that approximate -what microsoft calls- a bezier
1099  *   curve.
1100  *   The routine recursively divides the curve in two parts until a straight
1101  *   line can be drawn
1102  *
1103  *  PARAMS
1104  *
1105  *  Points  [I] Ptr to count POINTs which are the end and control points
1106  *              of the set of Bezier curves to flatten.
1107  *  count   [I] Number of Points.  Must be 3n+1.
1108  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1109  *              lines+1).
1110  *
1111  *  RETURNS
1112  *
1113  *  Ptr to an array of POINTs that contain the lines that approximinate the
1114  *  Beziers.  The array is allocated on the process heap and it is the caller's
1115  *  responsibility to HeapFree it. [this is not a particularly nice interface
1116  *  but since we can't know in advance how many points will generate, the
1117  *  alternative would be to call the function twice, once to determine the size
1118  *  and a second time to do the work - I decided this was too much of a pain].
1119  */
1120 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1121 {
1122     POINT *out;
1123     INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1124
1125     if (count == 1 || (count - 1) % 3 != 0) {
1126         ERR("Invalid no. of points %d\n", count);
1127         return NULL;
1128     }
1129     *nPtsOut = 0;
1130     out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1131     for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1132         POINT ptBuf[4];
1133         memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1134         for(i = 0; i < 4; i++) {
1135             ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1136             ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1137         }
1138         GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1139     }
1140     TRACE("Produced %d points\n", *nPtsOut);
1141     return out;
1142 }
1143
1144 /******************************************************************************
1145  *           GdiGradientFill   (GDI32.@)
1146  *
1147  *  FIXME: we don't support the Alpha channel properly
1148  */
1149 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1150                           void * grad_array, ULONG ngrad, ULONG mode )
1151 {
1152   unsigned int i;
1153
1154   TRACE("vert_array:0x%08lx nvert:%ld grad_array:0x%08lx ngrad:%ld\n",
1155         (long)vert_array, nvert, (long)grad_array, ngrad);
1156
1157   switch(mode) 
1158     {
1159     case GRADIENT_FILL_RECT_H:
1160       for(i = 0; i < ngrad; i++) 
1161         {
1162           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1163           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1164           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1165           int y1 = v1->y < v2->y ? v1->y : v2->y;
1166           int y2 = v2->y > v1->y ? v2->y : v1->y;
1167           int x, dx;
1168           if (v1->x > v2->x)
1169             {
1170               TRIVERTEX *t = v2;
1171               v2 = v1;
1172               v1 = t;
1173             }
1174           dx = v2->x - v1->x;
1175           for (x = 0; x < dx; x++)
1176             {
1177               POINT pts[2];
1178               HPEN hPen, hOldPen;
1179               
1180               hPen = CreatePen( PS_SOLID, 1, RGB(
1181                   (v1->Red   * (dx - x) + v2->Red   * x) / dx >> 8,
1182                   (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
1183                   (v1->Blue  * (dx - x) + v2->Blue  * x) / dx >> 8));
1184               hOldPen = SelectObject( hdc, hPen );
1185               pts[0].x = v1->x + x;
1186               pts[0].y = y1;
1187               pts[1].x = v1->x + x;
1188               pts[1].y = y2;
1189               Polyline( hdc, &pts[0], 2 );
1190               DeleteObject( SelectObject(hdc, hOldPen ) );
1191             }
1192         }
1193       break;
1194     case GRADIENT_FILL_RECT_V:
1195       for(i = 0; i < ngrad; i++) 
1196         {
1197           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1198           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1199           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1200           int x1 = v1->x < v2->x ? v1->x : v2->x;
1201           int x2 = v2->x > v1->x ? v2->x : v1->x;
1202           int y, dy;
1203           if (v1->y > v2->y)
1204             {
1205               TRIVERTEX *t = v2;
1206               v2 = v1;
1207               v1 = t;
1208             }
1209           dy = v2->y - v1->y;
1210           for (y = 0; y < dy; y++)
1211             {
1212               POINT pts[2];
1213               HPEN hPen, hOldPen;
1214               
1215               hPen = CreatePen( PS_SOLID, 1, RGB(
1216                   (v1->Red   * (dy - y) + v2->Red   * y) / dy >> 8,
1217                   (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
1218                   (v1->Blue  * (dy - y) + v2->Blue  * y) / dy >> 8));
1219               hOldPen = SelectObject( hdc, hPen );
1220               pts[0].x = x1;
1221               pts[0].y = v1->y + y;
1222               pts[1].x = x2;
1223               pts[1].y = v1->y + y;
1224               Polyline( hdc, &pts[0], 2 );
1225               DeleteObject( SelectObject(hdc, hOldPen ) );
1226             }
1227         }
1228       break;
1229     case GRADIENT_FILL_TRIANGLE:
1230       for (i = 0; i < ngrad; i++)  
1231         {
1232           GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
1233           TRIVERTEX *v1 = vert_array + tri->Vertex1;
1234           TRIVERTEX *v2 = vert_array + tri->Vertex2;
1235           TRIVERTEX *v3 = vert_array + tri->Vertex3;
1236           int y, dy;
1237           
1238           if (v1->y > v2->y)
1239             { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
1240           if (v2->y > v3->y)
1241             {
1242               TRIVERTEX *t = v2; v2 = v3; v3 = t;
1243               if (v1->y > v2->y)
1244                 { t = v1; v1 = v2; v2 = t; }
1245             }
1246           /* v1->y <= v2->y <= v3->y */
1247
1248           dy = v3->y - v1->y;
1249           for (y = 0; y < dy; y++)
1250             {
1251               /* v1->y <= y < v3->y */
1252               TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
1253               /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
1254               int dy2 = v2->y - v->y;
1255               int y2 = y + v1->y - v->y;
1256
1257               int x1 = (v3->x     * y  + v1->x     * (dy  - y )) / dy;
1258               int x2 = (v2->x     * y2 + v-> x     * (dy2 - y2)) / dy2;
1259               int r1 = (v3->Red   * y  + v1->Red   * (dy  - y )) / dy;
1260               int r2 = (v2->Red   * y2 + v-> Red   * (dy2 - y2)) / dy2;
1261               int g1 = (v3->Green * y  + v1->Green * (dy  - y )) / dy;
1262               int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
1263               int b1 = (v3->Blue  * y  + v1->Blue  * (dy  - y )) / dy;
1264               int b2 = (v2->Blue  * y2 + v-> Blue  * (dy2 - y2)) / dy2;
1265                
1266               int x;
1267               if (x1 < x2)
1268                 {
1269                   int dx = x2 - x1;
1270                   for (x = 0; x < dx; x++)
1271                     SetPixel (hdc, x + x1, y + v1->y, RGB(
1272                       (r1 * (dx - x) + r2 * x) / dx >> 8,
1273                       (g1 * (dx - x) + g2 * x) / dx >> 8,
1274                       (b1 * (dx - x) + b2 * x) / dx >> 8));
1275                 }
1276               else
1277                 {
1278                   int dx = x1 - x2;
1279                   for (x = 0; x < dx; x++)
1280                     SetPixel (hdc, x + x2, y + v1->y, RGB(
1281                       (r2 * (dx - x) + r1 * x) / dx >> 8,
1282                       (g2 * (dx - x) + g1 * x) / dx >> 8,
1283                       (b2 * (dx - x) + b1 * x) / dx >> 8));
1284                 }
1285             }
1286         }
1287       break;
1288     default:
1289       return FALSE;
1290   }
1291
1292   return TRUE;
1293 }