msvcp: Sync spec files.
[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) return FALSE;
156             if (types[i + 1] != PT_BEZIERTO) return FALSE;
157             if ((types[i + 2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO) return FALSE;
158             i += 2;
159             break;
160         default:
161             return FALSE;
162         }
163     }
164
165     space = count + 300;
166     line_pts = HeapAlloc( GetProcessHeap(), 0, space * sizeof(POINT) );
167     num_pts = 1;
168
169     GetCurrentPositionEx( dev->hdc, &line_pts[0] );
170     for (i = 0; i < count; i++)
171     {
172         switch (types[i])
173         {
174         case PT_MOVETO:
175             if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
176             num_pts = 0;
177             line_pts[num_pts++] = points[i];
178             break;
179         case PT_LINETO:
180         case (PT_LINETO | PT_CLOSEFIGURE):
181             line_pts[num_pts++] = points[i];
182             break;
183         case PT_BEZIERTO:
184             bzr[0].x = line_pts[num_pts - 1].x;
185             bzr[0].y = line_pts[num_pts - 1].y;
186             memcpy( &bzr[1], &points[i], 3 * sizeof(POINT) );
187
188             if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
189             {
190                 size = num_pts + (count - i) + num_bzr_pts;
191                 if (space < size)
192                 {
193                     space = size * 2;
194                     line_pts = HeapReAlloc( GetProcessHeap(), 0, line_pts, space * sizeof(POINT) );
195                 }
196                 memcpy( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
197                 num_pts += num_bzr_pts - 1;
198                 HeapFree( GetProcessHeap(), 0, bzr_pts );
199             }
200             i += 2;
201             break;
202         }
203         if (types[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
204     }
205
206     if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
207     MoveToEx( dev->hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
208     HeapFree( GetProcessHeap(), 0, line_pts );
209     return TRUE;
210 }
211
212 BOOL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
213 {
214     BOOL ret = FALSE;
215     POINT *pts;
216
217     if (!count) return FALSE;
218     if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
219     {
220         GetCurrentPositionEx( dev->hdc, &pts[0] );
221         memcpy( pts + 1, points, sizeof(POINT) * count );
222         ret = Polyline( dev->hdc, pts, count + 1 );
223         HeapFree( GetProcessHeap(), 0, pts );
224     }
225     return ret;
226 }
227
228 /***********************************************************************
229  *           LineTo    (GDI32.@)
230  */
231 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
232 {
233     DC * dc = get_dc_ptr( hdc );
234     PHYSDEV physdev;
235     BOOL ret;
236
237     if(!dc) return FALSE;
238
239     update_dc( dc );
240     physdev = GET_DC_PHYSDEV( dc, pLineTo );
241     ret = physdev->funcs->pLineTo( physdev, x, y );
242
243     if(ret) {
244         dc->CursPosX = x;
245         dc->CursPosY = y;
246     }
247     release_dc_ptr( dc );
248     return ret;
249 }
250
251
252 /***********************************************************************
253  *           MoveToEx    (GDI32.@)
254  */
255 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
256 {
257     BOOL ret;
258     PHYSDEV physdev;
259     DC * dc = get_dc_ptr( hdc );
260
261     if(!dc) return FALSE;
262
263     if(pt) {
264         pt->x = dc->CursPosX;
265         pt->y = dc->CursPosY;
266     }
267     dc->CursPosX = x;
268     dc->CursPosY = y;
269
270     physdev = GET_DC_PHYSDEV( dc, pMoveTo );
271     ret = physdev->funcs->pMoveTo( physdev, x, y );
272     release_dc_ptr( dc );
273     return ret;
274 }
275
276
277 /***********************************************************************
278  *           Arc    (GDI32.@)
279  */
280 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
281                      INT bottom, INT xstart, INT ystart,
282                      INT xend, INT yend )
283 {
284     PHYSDEV physdev;
285     BOOL ret;
286     DC * dc = get_dc_ptr( hdc );
287
288     if (!dc) return FALSE;
289     update_dc( dc );
290     physdev = GET_DC_PHYSDEV( dc, pArc );
291     ret = physdev->funcs->pArc( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
292     release_dc_ptr( dc );
293     return ret;
294 }
295
296 /***********************************************************************
297  *           ArcTo    (GDI32.@)
298  */
299 BOOL WINAPI ArcTo( HDC hdc,
300                      INT left,   INT top,
301                      INT right,  INT bottom,
302                      INT xstart, INT ystart,
303                      INT xend,   INT yend )
304 {
305     double width = fabs(right-left),
306         height = fabs(bottom-top),
307         xradius = width/2,
308         yradius = height/2,
309         xcenter = right > left ? left+xradius : right+xradius,
310         ycenter = bottom > top ? top+yradius : bottom+yradius,
311         angle;
312     PHYSDEV physdev;
313     BOOL result;
314     DC * dc = get_dc_ptr( hdc );
315     if(!dc) return FALSE;
316
317     update_dc( dc );
318     physdev = GET_DC_PHYSDEV( dc, pArcTo );
319     result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
320
321     if (result) {
322         angle = atan2(((yend-ycenter)/height),
323                       ((xend-xcenter)/width));
324         dc->CursPosX = GDI_ROUND(xcenter+(cos(angle)*xradius));
325         dc->CursPosY = GDI_ROUND(ycenter+(sin(angle)*yradius));
326     }
327     release_dc_ptr( dc );
328     return result;
329 }
330
331
332 /***********************************************************************
333  *           Pie   (GDI32.@)
334  */
335 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
336                      INT right, INT bottom, INT xstart, INT ystart,
337                      INT xend, INT yend )
338 {
339     BOOL ret;
340     PHYSDEV physdev;
341     DC * dc = get_dc_ptr( hdc );
342     if (!dc) return FALSE;
343
344     update_dc( dc );
345     physdev = GET_DC_PHYSDEV( dc, pPie );
346     ret = physdev->funcs->pPie( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
347     release_dc_ptr( dc );
348     return ret;
349 }
350
351
352 /***********************************************************************
353  *           Chord    (GDI32.@)
354  */
355 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
356                        INT right, INT bottom, INT xstart, INT ystart,
357                        INT xend, INT yend )
358 {
359     BOOL ret;
360     PHYSDEV physdev;
361     DC * dc = get_dc_ptr( hdc );
362     if (!dc) return FALSE;
363
364     update_dc( dc );
365     physdev = GET_DC_PHYSDEV( dc, pChord );
366     ret = physdev->funcs->pChord( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
367     release_dc_ptr( dc );
368     return ret;
369 }
370
371
372 /***********************************************************************
373  *           Ellipse    (GDI32.@)
374  */
375 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
376                          INT right, INT bottom )
377 {
378     BOOL ret;
379     PHYSDEV physdev;
380     DC * dc = get_dc_ptr( hdc );
381     if (!dc) return FALSE;
382
383     update_dc( dc );
384     physdev = GET_DC_PHYSDEV( dc, pEllipse );
385     ret = physdev->funcs->pEllipse( physdev, left, top, right, bottom );
386     release_dc_ptr( dc );
387     return ret;
388 }
389
390
391 /***********************************************************************
392  *           Rectangle    (GDI32.@)
393  */
394 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
395                            INT right, INT bottom )
396 {
397     PHYSDEV physdev;
398     BOOL ret;
399     DC * dc = get_dc_ptr( hdc );
400
401     if (!dc) return FALSE;
402     update_dc( dc );
403     physdev = GET_DC_PHYSDEV( dc, pRectangle );
404     ret = physdev->funcs->pRectangle( physdev, left, top, right, bottom );
405     release_dc_ptr( dc );
406     return ret;
407 }
408
409
410 /***********************************************************************
411  *           RoundRect    (GDI32.@)
412  */
413 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
414                            INT bottom, INT ell_width, INT ell_height )
415 {
416     PHYSDEV physdev;
417     BOOL ret;
418     DC *dc = get_dc_ptr( hdc );
419
420     if (!dc) return FALSE;
421     update_dc( dc );
422     physdev = GET_DC_PHYSDEV( dc, pRoundRect );
423     ret = physdev->funcs->pRoundRect( physdev, left, top, right, bottom, ell_width, ell_height );
424     release_dc_ptr( dc );
425     return ret;
426 }
427
428 /***********************************************************************
429  *           SetPixel    (GDI32.@)
430  */
431 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
432 {
433     PHYSDEV physdev;
434     COLORREF ret;
435     DC * dc = get_dc_ptr( hdc );
436
437     if (!dc) return 0;
438     update_dc( dc );
439     physdev = GET_DC_PHYSDEV( dc, pSetPixel );
440     ret = physdev->funcs->pSetPixel( physdev, x, y, color );
441     release_dc_ptr( dc );
442     return ret;
443 }
444
445 /***********************************************************************
446  *           SetPixelV    (GDI32.@)
447  */
448 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
449 {
450     PHYSDEV physdev;
451     DC * dc = get_dc_ptr( hdc );
452
453     if (!dc) return FALSE;
454     update_dc( dc );
455     physdev = GET_DC_PHYSDEV( dc, pSetPixel );
456     physdev->funcs->pSetPixel( physdev, x, y, color );
457     release_dc_ptr( dc );
458     return TRUE;
459 }
460
461 /***********************************************************************
462  *           GetPixel    (GDI32.@)
463  */
464 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
465 {
466     PHYSDEV physdev;
467     COLORREF ret;
468     DC * dc = get_dc_ptr( hdc );
469
470     if (!dc) return CLR_INVALID;
471     update_dc( dc );
472     physdev = GET_DC_PHYSDEV( dc, pGetPixel );
473     ret = physdev->funcs->pGetPixel( physdev, x, y );
474     release_dc_ptr( dc );
475     return ret;
476 }
477
478
479 /******************************************************************************
480  * GdiSetPixelFormat [GDI32.@]
481  *
482  * Probably not the correct semantics, it's supposed to be an internal backend for SetPixelFormat.
483  */
484 BOOL WINAPI GdiSetPixelFormat( HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr )
485 {
486     DC *dc;
487     BOOL ret = TRUE;
488
489     TRACE("(%p,%d,%p)\n", hdc, format, descr);
490
491     if (!(dc = get_dc_ptr( hdc ))) return FALSE;
492
493     if (!dc->pixel_format) dc->pixel_format = format;
494     else ret = (dc->pixel_format == format);
495     release_dc_ptr( dc );
496     return ret;
497 }
498
499
500 /******************************************************************************
501  * GdiDescribePixelFormat [GDI32.@]
502  *
503  * Probably not the correct semantics, it's supposed to be an internal backend for DescribePixelFormat.
504  */
505 INT WINAPI GdiDescribePixelFormat( HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR *descr )
506 {
507     FIXME( "(%p,%d,%d,%p): stub\n", hdc, format, size, descr );
508     return 0;
509 }
510
511
512 /******************************************************************************
513  * GdiSwapBuffers [GDI32.@]
514  *
515  * Probably not the correct semantics, it's supposed to be an internal backend for SwapBuffers.
516  */
517 BOOL WINAPI GdiSwapBuffers( HDC hdc )
518 {
519     FIXME( "(%p): stub\n", hdc );
520     return FALSE;
521 }
522
523
524 /***********************************************************************
525  *           PaintRgn    (GDI32.@)
526  */
527 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
528 {
529     PHYSDEV physdev;
530     BOOL ret;
531     DC * dc = get_dc_ptr( hdc );
532
533     if (!dc) return FALSE;
534     update_dc( dc );
535     physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
536     ret = physdev->funcs->pPaintRgn( physdev, hrgn );
537     release_dc_ptr( dc );
538     return ret;
539 }
540
541
542 /***********************************************************************
543  *           FillRgn    (GDI32.@)
544  */
545 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
546 {
547     PHYSDEV physdev;
548     BOOL retval;
549     DC * dc = get_dc_ptr( hdc );
550
551     if (!dc) return FALSE;
552     update_dc( dc );
553     physdev = GET_DC_PHYSDEV( dc, pFillRgn );
554     retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
555     release_dc_ptr( dc );
556     return retval;
557 }
558
559
560 /***********************************************************************
561  *           FrameRgn     (GDI32.@)
562  */
563 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
564                           INT nWidth, INT nHeight )
565 {
566     PHYSDEV physdev;
567     BOOL ret;
568     DC *dc = get_dc_ptr( hdc );
569
570     if (!dc) return FALSE;
571     update_dc( dc );
572     physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
573     ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
574     release_dc_ptr( dc );
575     return ret;
576 }
577
578
579 /***********************************************************************
580  *           InvertRgn    (GDI32.@)
581  */
582 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
583 {
584     PHYSDEV physdev;
585     BOOL ret;
586     DC *dc = get_dc_ptr( hdc );
587
588     if (!dc) return FALSE;
589     update_dc( dc );
590     physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
591     ret = physdev->funcs->pInvertRgn( physdev, hrgn );
592     release_dc_ptr( dc );
593     return ret;
594 }
595
596
597 /**********************************************************************
598  *          Polyline   (GDI32.@)
599  */
600 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
601 {
602     PHYSDEV physdev;
603     BOOL ret;
604     DC * dc = get_dc_ptr( hdc );
605
606     if (!dc) return FALSE;
607     update_dc( dc );
608     physdev = GET_DC_PHYSDEV( dc, pPolyline );
609     ret = physdev->funcs->pPolyline( physdev, pt, count );
610     release_dc_ptr( dc );
611     return ret;
612 }
613
614 /**********************************************************************
615  *          PolylineTo   (GDI32.@)
616  */
617 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
618 {
619     DC * dc = get_dc_ptr( hdc );
620     PHYSDEV physdev;
621     BOOL ret;
622
623     if(!dc) return FALSE;
624
625     update_dc( dc );
626     physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
627     ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
628
629     if (ret && cCount)
630     {
631         dc->CursPosX = pt[cCount-1].x;
632         dc->CursPosY = pt[cCount-1].y;
633     }
634     release_dc_ptr( dc );
635     return ret;
636 }
637
638
639 /**********************************************************************
640  *          Polygon  (GDI32.@)
641  */
642 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
643 {
644     PHYSDEV physdev;
645     BOOL ret;
646     DC * dc = get_dc_ptr( hdc );
647
648     if (!dc) return FALSE;
649     update_dc( dc );
650     physdev = GET_DC_PHYSDEV( dc, pPolygon );
651     ret = physdev->funcs->pPolygon( physdev, pt, count );
652     release_dc_ptr( dc );
653     return ret;
654 }
655
656
657 /**********************************************************************
658  *          PolyPolygon  (GDI32.@)
659  */
660 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
661                              UINT polygons )
662 {
663     PHYSDEV physdev;
664     BOOL ret;
665     DC * dc = get_dc_ptr( hdc );
666
667     if (!dc) return FALSE;
668     update_dc( dc );
669     physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
670     ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
671     release_dc_ptr( dc );
672     return ret;
673 }
674
675 /**********************************************************************
676  *          PolyPolyline  (GDI32.@)
677  */
678 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
679                             DWORD polylines )
680 {
681     PHYSDEV physdev;
682     BOOL ret;
683     DC * dc = get_dc_ptr( hdc );
684
685     if (!dc) return FALSE;
686     update_dc( dc );
687     physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
688     ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
689     release_dc_ptr( dc );
690     return ret;
691 }
692
693 /**********************************************************************
694  *          ExtFloodFill   (GDI32.@)
695  */
696 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
697                               UINT fillType )
698 {
699     PHYSDEV physdev;
700     BOOL ret;
701     DC * dc = get_dc_ptr( hdc );
702
703     if (!dc) return FALSE;
704     update_dc( dc );
705     physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );
706     ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
707     release_dc_ptr( dc );
708     return ret;
709 }
710
711
712 /**********************************************************************
713  *          FloodFill   (GDI32.@)
714  */
715 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
716 {
717     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
718 }
719
720
721 /******************************************************************************
722  * PolyBezier [GDI32.@]
723  * Draws one or more Bezier curves
724  *
725  * PARAMS
726  *    hDc     [I] Handle to device context
727  *    lppt    [I] Pointer to endpoints and control points
728  *    cPoints [I] Count of endpoints and control points
729  *
730  * RETURNS
731  *    Success: TRUE
732  *    Failure: FALSE
733  */
734 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
735 {
736     PHYSDEV physdev;
737     BOOL ret;
738     DC * dc;
739
740     /* cPoints must be 3 * n + 1 (where n>=1) */
741     if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
742
743     dc = get_dc_ptr( hdc );
744     if(!dc) return FALSE;
745
746     update_dc( dc );
747     physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
748     ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
749     release_dc_ptr( dc );
750     return ret;
751 }
752
753 /******************************************************************************
754  * PolyBezierTo [GDI32.@]
755  * Draws one or more Bezier curves
756  *
757  * PARAMS
758  *    hDc     [I] Handle to device context
759  *    lppt    [I] Pointer to endpoints and control points
760  *    cPoints [I] Count of endpoints and control points
761  *
762  * RETURNS
763  *    Success: TRUE
764  *    Failure: FALSE
765  */
766 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
767 {
768     DC * dc;
769     BOOL ret;
770     PHYSDEV physdev;
771
772     /* cbPoints must be 3 * n (where n>=1) */
773     if (!cPoints || (cPoints % 3) != 0) return FALSE;
774
775     dc = get_dc_ptr( hdc );
776     if(!dc) return FALSE;
777
778     update_dc( dc );
779     physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
780     ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
781
782     if(ret) {
783         dc->CursPosX = lppt[cPoints-1].x;
784         dc->CursPosY = lppt[cPoints-1].y;
785     }
786     release_dc_ptr( dc );
787     return ret;
788 }
789
790 /***********************************************************************
791  *      AngleArc (GDI32.@)
792  */
793 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
794 {
795     PHYSDEV physdev;
796     BOOL result;
797     DC *dc;
798
799     if( (signed int)dwRadius < 0 )
800         return FALSE;
801
802     dc = get_dc_ptr( hdc );
803     if(!dc) return FALSE;
804
805     update_dc( dc );
806     physdev = GET_DC_PHYSDEV( dc, pAngleArc );
807     result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
808
809     if (result) {
810         dc->CursPosX = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
811         dc->CursPosY = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
812     }
813     release_dc_ptr( dc );
814     return result;
815 }
816
817 /***********************************************************************
818  *      PolyDraw (GDI32.@)
819  */
820 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
821                        DWORD cCount)
822 {
823     DC *dc = get_dc_ptr( hdc );
824     PHYSDEV physdev;
825     BOOL result;
826
827     if(!dc) return FALSE;
828
829     update_dc( dc );
830     physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
831     result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
832     release_dc_ptr( dc );
833     return result;
834 }
835
836
837 /**********************************************************************
838  *           LineDDA   (GDI32.@)
839  */
840 BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
841                     LINEDDAPROC callback, LPARAM lParam )
842 {
843     INT xadd = 1, yadd = 1;
844     INT err,erradd;
845     INT cnt;
846     INT dx = nXEnd - nXStart;
847     INT dy = nYEnd - nYStart;
848
849     if (dx < 0)
850     {
851         dx = -dx;
852         xadd = -1;
853     }
854     if (dy < 0)
855     {
856         dy = -dy;
857         yadd = -1;
858     }
859     if (dx > dy)  /* line is "more horizontal" */
860     {
861         err = 2*dy - dx; erradd = 2*dy - 2*dx;
862         for(cnt = 0;cnt < dx; cnt++)
863         {
864             callback(nXStart,nYStart,lParam);
865             if (err > 0)
866             {
867                 nYStart += yadd;
868                 err += erradd;
869             }
870             else err += 2*dy;
871             nXStart += xadd;
872         }
873     }
874     else   /* line is "more vertical" */
875     {
876         err = 2*dx - dy; erradd = 2*dx - 2*dy;
877         for(cnt = 0;cnt < dy; cnt++)
878         {
879             callback(nXStart,nYStart,lParam);
880             if (err > 0)
881             {
882                 nXStart += xadd;
883                 err += erradd;
884             }
885             else err += 2*dx;
886             nYStart += yadd;
887         }
888     }
889     return TRUE;
890 }
891
892
893 /******************************************************************
894  *
895  *   *Very* simple bezier drawing code,
896  *
897  *   It uses a recursive algorithm to divide the curve in a series
898  *   of straight line segments. Not ideal but sufficient for me.
899  *   If you are in need for something better look for some incremental
900  *   algorithm.
901  *
902  *   7 July 1998 Rein Klazes
903  */
904
905  /*
906   * some macro definitions for bezier drawing
907   *
908   * to avoid truncation errors the coordinates are
909   * shifted upwards. When used in drawing they are
910   * shifted down again, including correct rounding
911   * and avoiding floating point arithmetic
912   * 4 bits should allow 27 bits coordinates which I saw
913   * somewhere in the win32 doc's
914   *
915   */
916
917 #define BEZIERSHIFTBITS 4
918 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
919 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
920 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
921 /* maximum depth of recursion */
922 #define BEZIERMAXDEPTH  8
923
924 /* size of array to store points on */
925 /* enough for one curve */
926 #define BEZIER_INITBUFSIZE    (150)
927
928 /* calculate Bezier average, in this case the middle
929  * correctly rounded...
930  * */
931
932 #define BEZIERMIDDLE(Mid, P1, P2) \
933     (Mid).x=((P1).x+(P2).x + 1)/2;\
934     (Mid).y=((P1).y+(P2).y + 1)/2;
935
936 /**********************************************************
937 * BezierCheck helper function to check
938 * that recursion can be terminated
939 *       Points[0] and Points[3] are begin and endpoint
940 *       Points[1] and Points[2] are control points
941 *       level is the recursion depth
942 *       returns true if the recursion can be terminated
943 */
944 static BOOL BezierCheck( int level, POINT *Points)
945 {
946     INT dx, dy;
947     dx=Points[3].x-Points[0].x;
948     dy=Points[3].y-Points[0].y;
949     if(abs(dy)<=abs(dx)){/* shallow line */
950         /* check that control points are between begin and end */
951         if(Points[1].x < Points[0].x){
952             if(Points[1].x < Points[3].x)
953                 return FALSE;
954         }else
955             if(Points[1].x > Points[3].x)
956                 return FALSE;
957         if(Points[2].x < Points[0].x){
958             if(Points[2].x < Points[3].x)
959                 return FALSE;
960         }else
961             if(Points[2].x > Points[3].x)
962                 return FALSE;
963         dx=BEZIERSHIFTDOWN(dx);
964         if(!dx) return TRUE;
965         if(abs(Points[1].y-Points[0].y-(dy/dx)*
966                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
967            abs(Points[2].y-Points[0].y-(dy/dx)*
968                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
969             return FALSE;
970         else
971             return TRUE;
972     }else{ /* steep line */
973         /* check that control points are between begin and end */
974         if(Points[1].y < Points[0].y){
975             if(Points[1].y < Points[3].y)
976                 return FALSE;
977         }else
978             if(Points[1].y > Points[3].y)
979                 return FALSE;
980         if(Points[2].y < Points[0].y){
981             if(Points[2].y < Points[3].y)
982                 return FALSE;
983         }else
984             if(Points[2].y > Points[3].y)
985                 return FALSE;
986         dy=BEZIERSHIFTDOWN(dy);
987         if(!dy) return TRUE;
988         if(abs(Points[1].x-Points[0].x-(dx/dy)*
989                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
990            abs(Points[2].x-Points[0].x-(dx/dy)*
991                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
992             return FALSE;
993         else
994             return TRUE;
995     }
996 }
997
998 /* Helper for GDI_Bezier.
999  * Just handles one Bezier, so Points should point to four POINTs
1000  */
1001 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1002                                 INT *nPtsOut, INT level )
1003 {
1004     if(*nPtsOut == *dwOut) {
1005         *dwOut *= 2;
1006         *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1007                                *dwOut * sizeof(POINT) );
1008     }
1009
1010     if(!level || BezierCheck(level, Points)) {
1011         if(*nPtsOut == 0) {
1012             (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1013             (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1014             *nPtsOut = 1;
1015         }
1016         (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1017         (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1018         (*nPtsOut) ++;
1019     } else {
1020         POINT Points2[4]; /* for the second recursive call */
1021         Points2[3]=Points[3];
1022         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1023         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1024         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1025
1026         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1027         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1028         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1029
1030         Points2[0]=Points[3];
1031
1032         /* do the two halves */
1033         GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1034         GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1035     }
1036 }
1037
1038
1039
1040 /***********************************************************************
1041  *           GDI_Bezier   [INTERNAL]
1042  *   Calculate line segments that approximate -what microsoft calls- a bezier
1043  *   curve.
1044  *   The routine recursively divides the curve in two parts until a straight
1045  *   line can be drawn
1046  *
1047  *  PARAMS
1048  *
1049  *  Points  [I] Ptr to count POINTs which are the end and control points
1050  *              of the set of Bezier curves to flatten.
1051  *  count   [I] Number of Points.  Must be 3n+1.
1052  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1053  *              lines+1).
1054  *
1055  *  RETURNS
1056  *
1057  *  Ptr to an array of POINTs that contain the lines that approximate the
1058  *  Beziers.  The array is allocated on the process heap and it is the caller's
1059  *  responsibility to HeapFree it. [this is not a particularly nice interface
1060  *  but since we can't know in advance how many points we will generate, the
1061  *  alternative would be to call the function twice, once to determine the size
1062  *  and a second time to do the work - I decided this was too much of a pain].
1063  */
1064 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1065 {
1066     POINT *out;
1067     INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1068
1069     if (count == 1 || (count - 1) % 3 != 0) {
1070         ERR("Invalid no. of points %d\n", count);
1071         return NULL;
1072     }
1073     *nPtsOut = 0;
1074     out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1075     for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1076         POINT ptBuf[4];
1077         memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1078         for(i = 0; i < 4; i++) {
1079             ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1080             ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1081         }
1082         GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1083     }
1084     TRACE("Produced %d points\n", *nPtsOut);
1085     return out;
1086 }
1087
1088 /******************************************************************************
1089  *           GdiGradientFill   (GDI32.@)
1090  */
1091 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1092                              void *grad_array, ULONG ngrad, ULONG mode )
1093 {
1094     DC *dc;
1095     PHYSDEV physdev;
1096     BOOL ret;
1097     ULONG i;
1098
1099     TRACE("%p vert_array:%p nvert:%d grad_array:%p ngrad:%d\n", hdc, vert_array, nvert, grad_array, ngrad);
1100
1101     if (!vert_array || !nvert || !grad_array || !ngrad || mode > GRADIENT_FILL_TRIANGLE)
1102     {
1103         SetLastError( ERROR_INVALID_PARAMETER );
1104         return FALSE;
1105     }
1106     for (i = 0; i < ngrad * (mode == GRADIENT_FILL_TRIANGLE ? 3 : 2); i++)
1107         if (((ULONG *)grad_array)[i] >= nvert) return FALSE;
1108
1109     if (!(dc = get_dc_ptr( hdc )))
1110     {
1111         SetLastError( ERROR_INVALID_PARAMETER );
1112         return FALSE;
1113     }
1114     update_dc( dc );
1115     physdev = GET_DC_PHYSDEV( dc, pGradientFill );
1116     ret = physdev->funcs->pGradientFill( physdev, vert_array, nvert, grad_array, ngrad, mode );
1117     release_dc_ptr( dc );
1118     return ret;
1119 }
1120
1121 /******************************************************************************
1122  *           GdiDrawStream   (GDI32.@)
1123  *
1124  */
1125 BOOL WINAPI GdiDrawStream( HDC hdc, ULONG in, void * pvin )
1126 {
1127     FIXME("stub: %p, %d, %p\n", hdc, in, pvin);
1128     return FALSE;
1129 }