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