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