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