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