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