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