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