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