gdi32: Add null driver entry points for SetDCBrush/PenColor.
[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) return 0;
549
550     if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
551     else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
552
553     release_dc_ptr( dc );
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) return 0;
580
581     update_dc( dc );
582     if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
583     else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
584
585     release_dc_ptr( dc );
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) return 0;
609
610     update_dc( dc );
611     if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
612     else ret = dc->funcs->pGetPixelFormat(dc->physDev);
613
614     release_dc_ptr( dc );
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) return 0;
642
643     update_dc( dc );
644     if (!dc->funcs->pDescribePixelFormat)
645     {
646         FIXME(" :stub\n");
647         ppfd->nSize = nBytes;
648         ppfd->nVersion = 1;
649         ret = 3;
650     }
651     else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
652
653     release_dc_ptr( dc );
654     return ret;
655 }
656
657
658 /******************************************************************************
659  * SwapBuffers [GDI32.@]
660  * Exchanges front and back buffers of window
661  *
662  * PARAMS
663  *    hdc [I] Device context whose buffers get swapped
664  *
665  * RETURNS
666  *    Success: TRUE
667  *    Failure: FALSE
668  */
669 BOOL WINAPI SwapBuffers( HDC hdc )
670 {
671     INT bRet = FALSE;
672     DC * dc = get_dc_ptr( hdc );
673
674     TRACE("(%p)\n",hdc);
675
676     if (!dc) return TRUE;
677
678     update_dc( dc );
679     if (!dc->funcs->pSwapBuffers)
680     {
681         FIXME(" :stub\n");
682         bRet = TRUE;
683     }
684     else bRet = dc->funcs->pSwapBuffers(dc->physDev);
685
686     release_dc_ptr( dc );
687     return bRet;
688 }
689
690
691 /***********************************************************************
692  *           PaintRgn    (GDI32.@)
693  */
694 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
695 {
696     BOOL ret = FALSE;
697     DC * dc = get_dc_ptr( hdc );
698
699     if (dc)
700     {
701         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
702         update_dc( dc );
703         ret = physdev->funcs->pPaintRgn( physdev, hrgn );
704         release_dc_ptr( dc );
705     }
706     return ret;
707 }
708
709
710 /***********************************************************************
711  *           FillRgn    (GDI32.@)
712  */
713 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
714 {
715     BOOL retval = FALSE;
716     DC * dc = get_dc_ptr( hdc );
717
718     if (dc)
719     {
720         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillRgn );
721         update_dc( dc );
722         retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
723         release_dc_ptr( dc );
724     }
725     return retval;
726 }
727
728
729 /***********************************************************************
730  *           FrameRgn     (GDI32.@)
731  */
732 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
733                           INT nWidth, INT nHeight )
734 {
735     BOOL ret = FALSE;
736     DC *dc = get_dc_ptr( hdc );
737
738     if (dc)
739     {
740         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
741         update_dc( dc );
742         ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
743         release_dc_ptr( dc );
744     }
745     return ret;
746 }
747
748
749 /***********************************************************************
750  *           InvertRgn    (GDI32.@)
751  */
752 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
753 {
754     BOOL ret = FALSE;
755     DC *dc = get_dc_ptr( hdc );
756
757     if (dc)
758     {
759         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
760         update_dc( dc );
761         ret = physdev->funcs->pInvertRgn( physdev, hrgn );
762         release_dc_ptr( dc );
763     }
764     return ret;
765 }
766
767
768 /**********************************************************************
769  *          Polyline   (GDI32.@)
770  */
771 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
772 {
773     BOOL ret = FALSE;
774     DC * dc = get_dc_ptr( hdc );
775
776     if (dc)
777     {
778         update_dc( dc );
779         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
780         else
781         {
782             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyline );
783             ret = physdev->funcs->pPolyline( physdev, pt, count );
784         }
785         release_dc_ptr( dc );
786     }
787     return ret;
788 }
789
790 /**********************************************************************
791  *          PolylineTo   (GDI32.@)
792  */
793 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
794 {
795     DC * dc = get_dc_ptr( hdc );
796     BOOL ret = FALSE;
797
798     if(!dc) return FALSE;
799
800     update_dc( dc );
801     if(PATH_IsPathOpen(dc->path)) ret = PATH_PolylineTo(dc, pt, cCount);
802     else
803     {
804         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
805         ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
806     }
807     if (ret && cCount)
808     {
809         dc->CursPosX = pt[cCount-1].x;
810         dc->CursPosY = pt[cCount-1].y;
811     }
812     release_dc_ptr( dc );
813     return ret;
814 }
815
816
817 /**********************************************************************
818  *          Polygon  (GDI32.@)
819  */
820 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
821 {
822     BOOL ret = FALSE;
823     DC * dc = get_dc_ptr( hdc );
824
825     if (dc)
826     {
827         update_dc( dc );
828         if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
829         else
830         {
831             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolygon );
832             ret = physdev->funcs->pPolygon( physdev, pt, count );
833         }
834         release_dc_ptr( dc );
835     }
836     return ret;
837 }
838
839
840 /**********************************************************************
841  *          PolyPolygon  (GDI32.@)
842  */
843 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
844                              UINT polygons )
845 {
846     BOOL ret = FALSE;
847     DC * dc = get_dc_ptr( hdc );
848
849     if (dc)
850     {
851         update_dc( dc );
852         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
853         else
854         {
855             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
856             ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
857         }
858         release_dc_ptr( dc );
859     }
860     return ret;
861 }
862
863 /**********************************************************************
864  *          PolyPolyline  (GDI32.@)
865  */
866 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
867                             DWORD polylines )
868 {
869     BOOL ret = FALSE;
870     DC * dc = get_dc_ptr( hdc );
871
872     if (dc)
873     {
874         update_dc( dc );
875         if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
876         else
877         {
878             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
879             ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
880         }
881         release_dc_ptr( dc );
882     }
883     return ret;
884 }
885
886 /**********************************************************************
887  *          ExtFloodFill   (GDI32.@)
888  */
889 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
890                               UINT fillType )
891 {
892     BOOL ret = FALSE;
893     DC * dc = get_dc_ptr( hdc );
894
895     if (dc)
896     {
897         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );
898
899         update_dc( dc );
900         ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
901         release_dc_ptr( dc );
902     }
903     return ret;
904 }
905
906
907 /**********************************************************************
908  *          FloodFill   (GDI32.@)
909  */
910 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
911 {
912     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
913 }
914
915
916 /******************************************************************************
917  * PolyBezier [GDI32.@]
918  * Draws one or more Bezier curves
919  *
920  * PARAMS
921  *    hDc     [I] Handle to device context
922  *    lppt    [I] Pointer to endpoints and control points
923  *    cPoints [I] Count of endpoints and control points
924  *
925  * RETURNS
926  *    Success: TRUE
927  *    Failure: FALSE
928  */
929 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
930 {
931     BOOL ret = FALSE;
932     DC * dc;
933
934     /* cPoints must be 3 * n + 1 (where n>=1) */
935     if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
936
937     dc = get_dc_ptr( hdc );
938     if(!dc) return FALSE;
939
940     update_dc( dc );
941     if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezier(dc, lppt, cPoints);
942     else
943     {
944         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
945         ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
946     }
947     release_dc_ptr( dc );
948     return ret;
949 }
950
951 /******************************************************************************
952  * PolyBezierTo [GDI32.@]
953  * Draws one or more Bezier curves
954  *
955  * PARAMS
956  *    hDc     [I] Handle to device context
957  *    lppt    [I] Pointer to endpoints and control points
958  *    cPoints [I] Count of endpoints and control points
959  *
960  * RETURNS
961  *    Success: TRUE
962  *    Failure: FALSE
963  */
964 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
965 {
966     DC * dc;
967     BOOL ret = FALSE;
968
969     /* cbPoints must be 3 * n (where n>=1) */
970     if (!cPoints || (cPoints % 3) != 0) return FALSE;
971
972     dc = get_dc_ptr( hdc );
973     if(!dc) return FALSE;
974
975     update_dc( dc );
976     if(PATH_IsPathOpen(dc->path)) ret = PATH_PolyBezierTo(dc, lppt, cPoints);
977     else
978     {
979         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
980         ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
981     }
982     if(ret) {
983         dc->CursPosX = lppt[cPoints-1].x;
984         dc->CursPosY = lppt[cPoints-1].y;
985     }
986     release_dc_ptr( dc );
987     return ret;
988 }
989
990 /***********************************************************************
991  *      AngleArc (GDI32.@)
992  */
993 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
994 {
995     INT x1,y1,x2,y2, arcdir;
996     BOOL result;
997     DC *dc;
998
999     if( (signed int)dwRadius < 0 )
1000         return FALSE;
1001
1002     dc = get_dc_ptr( hdc );
1003     if(!dc) return FALSE;
1004
1005     /* Calculate the end point */
1006     x2 = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
1007     y2 = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
1008
1009     update_dc( dc );
1010     if(!PATH_IsPathOpen(dc->path))
1011     {
1012         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pAngleArc );
1013         result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
1014     }
1015     else { /* do it using ArcTo */
1016         x1 = GDI_ROUND( x + cos(eStartAngle*M_PI/180) * dwRadius );
1017         y1 = GDI_ROUND( y - sin(eStartAngle*M_PI/180) * dwRadius );
1018
1019         arcdir = SetArcDirection( hdc, eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
1020         result = ArcTo( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1021                         x1, y1, x2, y2 );
1022         SetArcDirection( hdc, arcdir );
1023     }
1024     if (result) {
1025         dc->CursPosX = x2;
1026         dc->CursPosY = y2;
1027     }
1028     release_dc_ptr( dc );
1029     return result;
1030 }
1031
1032 /***********************************************************************
1033  *      PolyDraw (GDI32.@)
1034  */
1035 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1036                        DWORD cCount)
1037 {
1038     DC *dc = get_dc_ptr( hdc );
1039     BOOL result = FALSE;
1040
1041     if(!dc) return FALSE;
1042
1043     update_dc( dc );
1044     if( PATH_IsPathOpen( dc->path ) ) result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
1045     else
1046     {
1047         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
1048         result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
1049     }
1050     release_dc_ptr( dc );
1051     return result;
1052 }
1053
1054
1055 /**********************************************************************
1056  *           LineDDA   (GDI32.@)
1057  */
1058 BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
1059                     LINEDDAPROC callback, LPARAM lParam )
1060 {
1061     INT xadd = 1, yadd = 1;
1062     INT err,erradd;
1063     INT cnt;
1064     INT dx = nXEnd - nXStart;
1065     INT dy = nYEnd - nYStart;
1066
1067     if (dx < 0)
1068     {
1069         dx = -dx;
1070         xadd = -1;
1071     }
1072     if (dy < 0)
1073     {
1074         dy = -dy;
1075         yadd = -1;
1076     }
1077     if (dx > dy)  /* line is "more horizontal" */
1078     {
1079         err = 2*dy - dx; erradd = 2*dy - 2*dx;
1080         for(cnt = 0;cnt < dx; cnt++)
1081         {
1082             callback(nXStart,nYStart,lParam);
1083             if (err > 0)
1084             {
1085                 nYStart += yadd;
1086                 err += erradd;
1087             }
1088             else err += 2*dy;
1089             nXStart += xadd;
1090         }
1091     }
1092     else   /* line is "more vertical" */
1093     {
1094         err = 2*dx - dy; erradd = 2*dx - 2*dy;
1095         for(cnt = 0;cnt < dy; cnt++)
1096         {
1097             callback(nXStart,nYStart,lParam);
1098             if (err > 0)
1099             {
1100                 nXStart += xadd;
1101                 err += erradd;
1102             }
1103             else err += 2*dx;
1104             nYStart += yadd;
1105         }
1106     }
1107     return TRUE;
1108 }
1109
1110
1111 /******************************************************************
1112  *
1113  *   *Very* simple bezier drawing code,
1114  *
1115  *   It uses a recursive algorithm to divide the curve in a series
1116  *   of straight line segments. Not ideal but sufficient for me.
1117  *   If you are in need for something better look for some incremental
1118  *   algorithm.
1119  *
1120  *   7 July 1998 Rein Klazes
1121  */
1122
1123  /*
1124   * some macro definitions for bezier drawing
1125   *
1126   * to avoid truncation errors the coordinates are
1127   * shifted upwards. When used in drawing they are
1128   * shifted down again, including correct rounding
1129   * and avoiding floating point arithmetic
1130   * 4 bits should allow 27 bits coordinates which I saw
1131   * somewhere in the win32 doc's
1132   *
1133   */
1134
1135 #define BEZIERSHIFTBITS 4
1136 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
1137 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
1138 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1139 /* maximum depth of recursion */
1140 #define BEZIERMAXDEPTH  8
1141
1142 /* size of array to store points on */
1143 /* enough for one curve */
1144 #define BEZIER_INITBUFSIZE    (150)
1145
1146 /* calculate Bezier average, in this case the middle
1147  * correctly rounded...
1148  * */
1149
1150 #define BEZIERMIDDLE(Mid, P1, P2) \
1151     (Mid).x=((P1).x+(P2).x + 1)/2;\
1152     (Mid).y=((P1).y+(P2).y + 1)/2;
1153
1154 /**********************************************************
1155 * BezierCheck helper function to check
1156 * that recursion can be terminated
1157 *       Points[0] and Points[3] are begin and endpoint
1158 *       Points[1] and Points[2] are control points
1159 *       level is the recursion depth
1160 *       returns true if the recursion can be terminated
1161 */
1162 static BOOL BezierCheck( int level, POINT *Points)
1163 {
1164     INT dx, dy;
1165     dx=Points[3].x-Points[0].x;
1166     dy=Points[3].y-Points[0].y;
1167     if(abs(dy)<=abs(dx)){/* shallow line */
1168         /* check that control points are between begin and end */
1169         if(Points[1].x < Points[0].x){
1170             if(Points[1].x < Points[3].x)
1171                 return FALSE;
1172         }else
1173             if(Points[1].x > Points[3].x)
1174                 return FALSE;
1175         if(Points[2].x < Points[0].x){
1176             if(Points[2].x < Points[3].x)
1177                 return FALSE;
1178         }else
1179             if(Points[2].x > Points[3].x)
1180                 return FALSE;
1181         dx=BEZIERSHIFTDOWN(dx);
1182         if(!dx) return TRUE;
1183         if(abs(Points[1].y-Points[0].y-(dy/dx)*
1184                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1185            abs(Points[2].y-Points[0].y-(dy/dx)*
1186                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1187             return FALSE;
1188         else
1189             return TRUE;
1190     }else{ /* steep line */
1191         /* check that control points are between begin and end */
1192         if(Points[1].y < Points[0].y){
1193             if(Points[1].y < Points[3].y)
1194                 return FALSE;
1195         }else
1196             if(Points[1].y > Points[3].y)
1197                 return FALSE;
1198         if(Points[2].y < Points[0].y){
1199             if(Points[2].y < Points[3].y)
1200                 return FALSE;
1201         }else
1202             if(Points[2].y > Points[3].y)
1203                 return FALSE;
1204         dy=BEZIERSHIFTDOWN(dy);
1205         if(!dy) return TRUE;
1206         if(abs(Points[1].x-Points[0].x-(dx/dy)*
1207                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1208            abs(Points[2].x-Points[0].x-(dx/dy)*
1209                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1210             return FALSE;
1211         else
1212             return TRUE;
1213     }
1214 }
1215
1216 /* Helper for GDI_Bezier.
1217  * Just handles one Bezier, so Points should point to four POINTs
1218  */
1219 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1220                                 INT *nPtsOut, INT level )
1221 {
1222     if(*nPtsOut == *dwOut) {
1223         *dwOut *= 2;
1224         *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1225                                *dwOut * sizeof(POINT) );
1226     }
1227
1228     if(!level || BezierCheck(level, Points)) {
1229         if(*nPtsOut == 0) {
1230             (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1231             (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1232             *nPtsOut = 1;
1233         }
1234         (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1235         (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1236         (*nPtsOut) ++;
1237     } else {
1238         POINT Points2[4]; /* for the second recursive call */
1239         Points2[3]=Points[3];
1240         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1241         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1242         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1243
1244         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1245         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1246         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1247
1248         Points2[0]=Points[3];
1249
1250         /* do the two halves */
1251         GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1252         GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1253     }
1254 }
1255
1256
1257
1258 /***********************************************************************
1259  *           GDI_Bezier   [INTERNAL]
1260  *   Calculate line segments that approximate -what microsoft calls- a bezier
1261  *   curve.
1262  *   The routine recursively divides the curve in two parts until a straight
1263  *   line can be drawn
1264  *
1265  *  PARAMS
1266  *
1267  *  Points  [I] Ptr to count POINTs which are the end and control points
1268  *              of the set of Bezier curves to flatten.
1269  *  count   [I] Number of Points.  Must be 3n+1.
1270  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1271  *              lines+1).
1272  *
1273  *  RETURNS
1274  *
1275  *  Ptr to an array of POINTs that contain the lines that approximate the
1276  *  Beziers.  The array is allocated on the process heap and it is the caller's
1277  *  responsibility to HeapFree it. [this is not a particularly nice interface
1278  *  but since we can't know in advance how many points we will generate, the
1279  *  alternative would be to call the function twice, once to determine the size
1280  *  and a second time to do the work - I decided this was too much of a pain].
1281  */
1282 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1283 {
1284     POINT *out;
1285     INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1286
1287     if (count == 1 || (count - 1) % 3 != 0) {
1288         ERR("Invalid no. of points %d\n", count);
1289         return NULL;
1290     }
1291     *nPtsOut = 0;
1292     out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1293     for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1294         POINT ptBuf[4];
1295         memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1296         for(i = 0; i < 4; i++) {
1297             ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1298             ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1299         }
1300         GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1301     }
1302     TRACE("Produced %d points\n", *nPtsOut);
1303     return out;
1304 }
1305
1306 /******************************************************************************
1307  *           GdiGradientFill   (GDI32.@)
1308  *
1309  *  FIXME: we don't support the Alpha channel properly
1310  */
1311 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1312                           void * grad_array, ULONG ngrad, ULONG mode )
1313 {
1314   unsigned int i;
1315
1316   TRACE("vert_array:%p nvert:%d grad_array:%p ngrad:%d\n",
1317         vert_array, nvert, grad_array, ngrad);
1318
1319   switch(mode) 
1320     {
1321     case GRADIENT_FILL_RECT_H:
1322       for(i = 0; i < ngrad; i++) 
1323         {
1324           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1325           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1326           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1327           int y1 = v1->y < v2->y ? v1->y : v2->y;
1328           int y2 = v2->y > v1->y ? v2->y : v1->y;
1329           int x, dx;
1330           if (v1->x > v2->x)
1331             {
1332               TRIVERTEX *t = v2;
1333               v2 = v1;
1334               v1 = t;
1335             }
1336           dx = v2->x - v1->x;
1337           for (x = 0; x < dx; x++)
1338             {
1339               POINT pts[2];
1340               HPEN hPen, hOldPen;
1341               
1342               hPen = CreatePen( PS_SOLID, 1, RGB(
1343                   (v1->Red   * (dx - x) + v2->Red   * x) / dx >> 8,
1344                   (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
1345                   (v1->Blue  * (dx - x) + v2->Blue  * x) / dx >> 8));
1346               hOldPen = SelectObject( hdc, hPen );
1347               pts[0].x = v1->x + x;
1348               pts[0].y = y1;
1349               pts[1].x = v1->x + x;
1350               pts[1].y = y2;
1351               Polyline( hdc, &pts[0], 2 );
1352               DeleteObject( SelectObject(hdc, hOldPen ) );
1353             }
1354         }
1355       break;
1356     case GRADIENT_FILL_RECT_V:
1357       for(i = 0; i < ngrad; i++) 
1358         {
1359           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1360           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1361           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1362           int x1 = v1->x < v2->x ? v1->x : v2->x;
1363           int x2 = v2->x > v1->x ? v2->x : v1->x;
1364           int y, dy;
1365           if (v1->y > v2->y)
1366             {
1367               TRIVERTEX *t = v2;
1368               v2 = v1;
1369               v1 = t;
1370             }
1371           dy = v2->y - v1->y;
1372           for (y = 0; y < dy; y++)
1373             {
1374               POINT pts[2];
1375               HPEN hPen, hOldPen;
1376               
1377               hPen = CreatePen( PS_SOLID, 1, RGB(
1378                   (v1->Red   * (dy - y) + v2->Red   * y) / dy >> 8,
1379                   (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
1380                   (v1->Blue  * (dy - y) + v2->Blue  * y) / dy >> 8));
1381               hOldPen = SelectObject( hdc, hPen );
1382               pts[0].x = x1;
1383               pts[0].y = v1->y + y;
1384               pts[1].x = x2;
1385               pts[1].y = v1->y + y;
1386               Polyline( hdc, &pts[0], 2 );
1387               DeleteObject( SelectObject(hdc, hOldPen ) );
1388             }
1389         }
1390       break;
1391     case GRADIENT_FILL_TRIANGLE:
1392       for (i = 0; i < ngrad; i++)  
1393         {
1394           GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
1395           TRIVERTEX *v1 = vert_array + tri->Vertex1;
1396           TRIVERTEX *v2 = vert_array + tri->Vertex2;
1397           TRIVERTEX *v3 = vert_array + tri->Vertex3;
1398           int y, dy;
1399           
1400           if (v1->y > v2->y)
1401             { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
1402           if (v2->y > v3->y)
1403             {
1404               TRIVERTEX *t = v2; v2 = v3; v3 = t;
1405               if (v1->y > v2->y)
1406                 { t = v1; v1 = v2; v2 = t; }
1407             }
1408           /* v1->y <= v2->y <= v3->y */
1409
1410           dy = v3->y - v1->y;
1411           for (y = 0; y < dy; y++)
1412             {
1413               /* v1->y <= y < v3->y */
1414               TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
1415               /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
1416               int dy2 = v2->y - v->y;
1417               int y2 = y + v1->y - v->y;
1418
1419               int x1 = (v3->x     * y  + v1->x     * (dy  - y )) / dy;
1420               int x2 = (v2->x     * y2 + v-> x     * (dy2 - y2)) / dy2;
1421               int r1 = (v3->Red   * y  + v1->Red   * (dy  - y )) / dy;
1422               int r2 = (v2->Red   * y2 + v-> Red   * (dy2 - y2)) / dy2;
1423               int g1 = (v3->Green * y  + v1->Green * (dy  - y )) / dy;
1424               int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
1425               int b1 = (v3->Blue  * y  + v1->Blue  * (dy  - y )) / dy;
1426               int b2 = (v2->Blue  * y2 + v-> Blue  * (dy2 - y2)) / dy2;
1427                
1428               int x;
1429               if (x1 < x2)
1430                 {
1431                   int dx = x2 - x1;
1432                   for (x = 0; x < dx; x++)
1433                     SetPixel (hdc, x + x1, y + v1->y, RGB(
1434                       (r1 * (dx - x) + r2 * x) / dx >> 8,
1435                       (g1 * (dx - x) + g2 * x) / dx >> 8,
1436                       (b1 * (dx - x) + b2 * x) / dx >> 8));
1437                 }
1438               else
1439                 {
1440                   int dx = x1 - x2;
1441                   for (x = 0; x < dx; x++)
1442                     SetPixel (hdc, x + x2, y + v1->y, RGB(
1443                       (r2 * (dx - x) + r1 * x) / dx >> 8,
1444                       (g2 * (dx - x) + g1 * x) / dx >> 8,
1445                       (b2 * (dx - x) + b1 * x) / dx >> 8));
1446                 }
1447             }
1448         }
1449       break;
1450     default:
1451       return FALSE;
1452   }
1453
1454   return TRUE;
1455 }
1456
1457 /******************************************************************************
1458  *           GdiDrawStream   (GDI32.@)
1459  *
1460  */
1461 BOOL WINAPI GdiDrawStream( HDC hdc, ULONG in, void * pvin )
1462 {
1463     FIXME("stub: %p, %d, %p\n", hdc, in, pvin);
1464     return FALSE;
1465 }