gdi32: Emulate DDB support using the DIB driver when the graphics driver doesn't...
[wine] / dlls / gdi32 / painting.c
1 /*
2  * GDI drawing functions.
3  *
4  * Copyright 1993, 1994 Alexandre Julliard
5  * Copyright 1997 Bertho A. Stultiens
6  *           1999 Huw D M Davies
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "gdi_private.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
38
39
40 /***********************************************************************
41  *           null driver fallback implementations
42  */
43
44 BOOL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
45 {
46     INT x1 = GDI_ROUND( x + cos( start * M_PI / 180 ) * radius );
47     INT y1 = GDI_ROUND( y - sin( start * M_PI / 180 ) * radius );
48     INT x2 = GDI_ROUND( x + cos( (start + sweep) * M_PI / 180) * radius );
49     INT y2 = GDI_ROUND( y - sin( (start + sweep) * M_PI / 180) * radius );
50     INT arcdir = SetArcDirection( dev->hdc, sweep >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE );
51     BOOL ret = ArcTo( dev->hdc, x - radius, y - radius, x + radius, y + radius, x1, y1, x2, y2 );
52     SetArcDirection( dev->hdc, arcdir );
53     return ret;
54 }
55
56 BOOL nulldrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
57                     INT xstart, INT ystart, INT xend, INT yend )
58 {
59     INT width = abs( right - left );
60     INT height = abs( bottom - top );
61     double xradius = width / 2.0;
62     double yradius = height / 2.0;
63     double xcenter = right > left ? left + xradius : right + xradius;
64     double ycenter = bottom > top ? top + yradius : bottom + yradius;
65     double angle;
66
67     if (!height || !width) return FALSE;
68     /* draw a line from the current position to the starting point of the arc, then draw the arc */
69     angle = atan2( (ystart - ycenter) / height, (xstart - xcenter) / width );
70     LineTo( dev->hdc, GDI_ROUND( xcenter + cos(angle) * xradius ),
71             GDI_ROUND( ycenter + sin(angle) * yradius ));
72     return Arc( dev->hdc, left, top, right, bottom, xstart, ystart, xend, yend );
73 }
74
75 BOOL nulldrv_FillRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush )
76 {
77     BOOL ret = FALSE;
78     HBRUSH prev;
79
80     if ((prev = SelectObject( dev->hdc, brush )))
81     {
82         ret = PaintRgn( dev->hdc, rgn );
83         SelectObject( dev->hdc, prev );
84     }
85     return ret;
86 }
87
88 BOOL nulldrv_FrameRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush, INT width, INT height )
89 {
90     BOOL ret = FALSE;
91     HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
92
93     if (tmp)
94     {
95         if (REGION_FrameRgn( tmp, rgn, width, height )) ret = FillRgn( dev->hdc, tmp, brush );
96         DeleteObject( tmp );
97     }
98     return ret;
99 }
100
101 BOOL nulldrv_InvertRgn( PHYSDEV dev, HRGN rgn )
102 {
103     HBRUSH prev_brush = SelectObject( dev->hdc, GetStockObject(BLACK_BRUSH) );
104     INT prev_rop = SetROP2( dev->hdc, R2_NOT );
105     BOOL ret = PaintRgn( dev->hdc, rgn );
106     SelectObject( dev->hdc, prev_brush );
107     SetROP2( dev->hdc, prev_rop );
108     return ret;
109 }
110
111 BOOL nulldrv_PolyBezier( PHYSDEV dev, const POINT *points, DWORD count )
112 {
113     BOOL ret = FALSE;
114     POINT *pts;
115     INT n;
116
117     if ((pts = GDI_Bezier( points, count, &n )))
118     {
119         ret = Polyline( dev->hdc, pts, n );
120         HeapFree( GetProcessHeap(), 0, pts );
121     }
122     return ret;
123 }
124
125 BOOL nulldrv_PolyBezierTo( PHYSDEV dev, const POINT *points, DWORD count )
126 {
127     BOOL ret = FALSE;
128     POINT *pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) );
129
130     if (pts)
131     {
132         GetCurrentPositionEx( dev->hdc, &pts[0] );
133         memcpy( pts + 1, points, sizeof(POINT) * count );
134         ret = PolyBezier( dev->hdc, pts, count + 1 );
135         HeapFree( GetProcessHeap(), 0, pts );
136     }
137     return ret;
138 }
139
140 BOOL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count )
141 {
142     POINT *line_pts = NULL, *bzr_pts = NULL, bzr[4];
143     INT i, num_pts, num_bzr_pts, space, size;
144
145     /* check for valid point types */
146     for (i = 0; i < count; i++)
147     {
148         switch (types[i])
149         {
150         case PT_MOVETO:
151         case PT_LINETO | PT_CLOSEFIGURE:
152         case PT_LINETO:
153             break;
154         case PT_BEZIERTO:
155             if((i + 2 < count) && (types[i + 1] == PT_BEZIERTO) &&
156                ((types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
157             {
158                 i += 2;
159                 break;
160             }
161         default:
162             return FALSE;
163         }
164     }
165
166     space = count + 300;
167     line_pts = HeapAlloc( GetProcessHeap(), 0, space * sizeof(POINT) );
168     num_pts = 1;
169
170     GetCurrentPositionEx( dev->hdc, &line_pts[0] );
171     for (i = 0; i < count; i++)
172     {
173         switch (types[i])
174         {
175         case PT_MOVETO:
176             if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
177             num_pts = 0;
178             line_pts[num_pts++] = points[i];
179             break;
180         case PT_LINETO:
181         case (PT_LINETO | PT_CLOSEFIGURE):
182             line_pts[num_pts++] = points[i];
183             break;
184         case PT_BEZIERTO:
185             bzr[0].x = line_pts[num_pts - 1].x;
186             bzr[0].y = line_pts[num_pts - 1].y;
187             memcpy( &bzr[1], &points[i], 3 * sizeof(POINT) );
188
189             if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
190             {
191                 size = num_pts + (count - i) + num_bzr_pts;
192                 if (space < size)
193                 {
194                     space = size * 2;
195                     line_pts = HeapReAlloc( GetProcessHeap(), 0, line_pts, space * sizeof(POINT) );
196                 }
197                 memcpy( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
198                 num_pts += num_bzr_pts - 1;
199                 HeapFree( GetProcessHeap(), 0, bzr_pts );
200             }
201             i += 2;
202             break;
203         }
204         if (types[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
205     }
206
207     if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
208     MoveToEx( dev->hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
209     HeapFree( GetProcessHeap(), 0, line_pts );
210     return TRUE;
211 }
212
213 BOOL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
214 {
215     BOOL ret = FALSE;
216     POINT *pts;
217
218     if (!count) return FALSE;
219     if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
220     {
221         GetCurrentPositionEx( dev->hdc, &pts[0] );
222         memcpy( pts + 1, points, sizeof(POINT) * count );
223         ret = Polyline( dev->hdc, pts, count + 1 );
224         HeapFree( GetProcessHeap(), 0, pts );
225     }
226     return ret;
227 }
228
229 /***********************************************************************
230  *           LineTo    (GDI32.@)
231  */
232 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
233 {
234     DC * dc = get_dc_ptr( hdc );
235     PHYSDEV physdev;
236     BOOL ret;
237
238     if(!dc) return FALSE;
239
240     update_dc( dc );
241     physdev = GET_DC_PHYSDEV( dc, pLineTo );
242     ret = physdev->funcs->pLineTo( physdev, x, y );
243
244     if(ret) {
245         dc->CursPosX = x;
246         dc->CursPosY = y;
247     }
248     release_dc_ptr( dc );
249     return ret;
250 }
251
252
253 /***********************************************************************
254  *           MoveToEx    (GDI32.@)
255  */
256 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
257 {
258     BOOL ret;
259     PHYSDEV physdev;
260     DC * dc = get_dc_ptr( hdc );
261
262     if(!dc) return FALSE;
263
264     if(pt) {
265         pt->x = dc->CursPosX;
266         pt->y = dc->CursPosY;
267     }
268     dc->CursPosX = x;
269     dc->CursPosY = y;
270
271     physdev = GET_DC_PHYSDEV( dc, pMoveTo );
272     ret = physdev->funcs->pMoveTo( physdev, x, y );
273     release_dc_ptr( dc );
274     return ret;
275 }
276
277
278 /***********************************************************************
279  *           Arc    (GDI32.@)
280  */
281 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
282                      INT bottom, INT xstart, INT ystart,
283                      INT xend, INT yend )
284 {
285     BOOL ret = FALSE;
286     DC * dc = get_dc_ptr( hdc );
287
288     if (dc)
289     {
290         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pArc );
291         update_dc( dc );
292         ret = physdev->funcs->pArc( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
293         release_dc_ptr( dc );
294     }
295     return ret;
296 }
297
298 /***********************************************************************
299  *           ArcTo    (GDI32.@)
300  */
301 BOOL WINAPI ArcTo( HDC hdc,
302                      INT left,   INT top,
303                      INT right,  INT bottom,
304                      INT xstart, INT ystart,
305                      INT xend,   INT yend )
306 {
307     double width = fabs(right-left),
308         height = fabs(bottom-top),
309         xradius = width/2,
310         yradius = height/2,
311         xcenter = right > left ? left+xradius : right+xradius,
312         ycenter = bottom > top ? top+yradius : bottom+yradius,
313         angle;
314     PHYSDEV physdev;
315     BOOL result;
316     DC * dc = get_dc_ptr( hdc );
317     if(!dc) return FALSE;
318
319     update_dc( dc );
320     physdev = GET_DC_PHYSDEV( dc, pArcTo );
321     result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
322
323     if (result) {
324         angle = atan2(((yend-ycenter)/height),
325                       ((xend-xcenter)/width));
326         dc->CursPosX = GDI_ROUND(xcenter+(cos(angle)*xradius));
327         dc->CursPosY = GDI_ROUND(ycenter+(sin(angle)*yradius));
328     }
329     release_dc_ptr( dc );
330     return result;
331 }
332
333
334 /***********************************************************************
335  *           Pie   (GDI32.@)
336  */
337 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
338                      INT right, INT bottom, INT xstart, INT ystart,
339                      INT xend, INT yend )
340 {
341     BOOL ret;
342     PHYSDEV physdev;
343     DC * dc = get_dc_ptr( hdc );
344     if (!dc) return FALSE;
345
346     update_dc( dc );
347     physdev = GET_DC_PHYSDEV( dc, pPie );
348     ret = physdev->funcs->pPie( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
349     release_dc_ptr( dc );
350     return ret;
351 }
352
353
354 /***********************************************************************
355  *           Chord    (GDI32.@)
356  */
357 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
358                        INT right, INT bottom, INT xstart, INT ystart,
359                        INT xend, INT yend )
360 {
361     BOOL ret;
362     PHYSDEV physdev;
363     DC * dc = get_dc_ptr( hdc );
364     if (!dc) return FALSE;
365
366     update_dc( dc );
367     physdev = GET_DC_PHYSDEV( dc, pChord );
368     ret = physdev->funcs->pChord( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
369     release_dc_ptr( dc );
370     return ret;
371 }
372
373
374 /***********************************************************************
375  *           Ellipse    (GDI32.@)
376  */
377 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
378                          INT right, INT bottom )
379 {
380     BOOL ret;
381     PHYSDEV physdev;
382     DC * dc = get_dc_ptr( hdc );
383     if (!dc) return FALSE;
384
385     update_dc( dc );
386     physdev = GET_DC_PHYSDEV( dc, pEllipse );
387     ret = physdev->funcs->pEllipse( physdev, left, top, right, bottom );
388     release_dc_ptr( dc );
389     return ret;
390 }
391
392
393 /***********************************************************************
394  *           Rectangle    (GDI32.@)
395  */
396 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
397                            INT right, INT bottom )
398 {
399     BOOL ret = FALSE;
400     DC * dc = get_dc_ptr( hdc );
401
402     if (dc)
403     {
404         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRectangle );
405         update_dc( dc );
406         ret = physdev->funcs->pRectangle( physdev, left, top, right, bottom );
407         release_dc_ptr( dc );
408     }
409     return ret;
410 }
411
412
413 /***********************************************************************
414  *           RoundRect    (GDI32.@)
415  */
416 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
417                            INT bottom, INT ell_width, INT ell_height )
418 {
419     BOOL ret = FALSE;
420     DC *dc = get_dc_ptr( hdc );
421
422     if (dc)
423     {
424         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRoundRect );
425         update_dc( dc );
426         ret = physdev->funcs->pRoundRect( physdev, left, top, right, bottom, ell_width, ell_height );
427         release_dc_ptr( dc );
428     }
429     return ret;
430 }
431
432 /***********************************************************************
433  *           SetPixel    (GDI32.@)
434  */
435 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
436 {
437     COLORREF ret = 0;
438     DC * dc = get_dc_ptr( hdc );
439
440     if (dc)
441     {
442         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
443         update_dc( dc );
444         ret = physdev->funcs->pSetPixel( physdev, x, y, color );
445         release_dc_ptr( dc );
446     }
447     return ret;
448 }
449
450 /***********************************************************************
451  *           SetPixelV    (GDI32.@)
452  */
453 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
454 {
455     BOOL ret = FALSE;
456     DC * dc = get_dc_ptr( hdc );
457
458     if (dc)
459     {
460         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
461         update_dc( dc );
462         physdev->funcs->pSetPixel( physdev, x, y, color );
463         ret = TRUE;
464         release_dc_ptr( dc );
465     }
466     return ret;
467 }
468
469 /***********************************************************************
470  *           GetPixel    (GDI32.@)
471  */
472 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
473 {
474     COLORREF ret = CLR_INVALID;
475     DC * dc = get_dc_ptr( hdc );
476
477     if (dc)
478     {
479         update_dc( dc );
480         /* FIXME: should this be in the graphics driver? */
481         if (PtVisible( hdc, x, y ))
482         {
483             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixel );
484             ret = physdev->funcs->pGetPixel( physdev, x, y );
485         }
486         release_dc_ptr( dc );
487     }
488     return ret;
489 }
490
491
492 /******************************************************************************
493  * ChoosePixelFormat [GDI32.@]
494  * Matches a pixel format to given format
495  *
496  * PARAMS
497  *    hdc  [I] Device context to search for best pixel match
498  *    ppfd [I] Pixel format for which a match is sought
499  *
500  * RETURNS
501  *    Success: Pixel format index closest to given format
502  *    Failure: 0
503  */
504 INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
505 {
506     INT ret = 0;
507     DC * dc = get_dc_ptr( hdc );
508
509     TRACE("(%p,%p)\n",hdc,ppfd);
510
511     if (dc)
512     {
513         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pChoosePixelFormat );
514         ret = physdev->funcs->pChoosePixelFormat( physdev, ppfd );
515         release_dc_ptr( dc );
516     }
517     return ret;
518 }
519
520
521 /******************************************************************************
522  * SetPixelFormat [GDI32.@]
523  * Sets pixel format of device context
524  *
525  * PARAMS
526  *    hdc          [I] Device context to search for best pixel match
527  *    iPixelFormat [I] Pixel format index
528  *    ppfd         [I] Pixel format for which a match is sought
529  *
530  * RETURNS
531  *    Success: TRUE
532  *    Failure: FALSE
533  */
534 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
535                             const PIXELFORMATDESCRIPTOR *ppfd)
536 {
537     INT bRet = FALSE;
538     DC * dc = get_dc_ptr( hdc );
539
540     TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
541
542     if (dc)
543     {
544         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixelFormat );
545         update_dc( dc );
546         bRet = physdev->funcs->pSetPixelFormat( physdev, iPixelFormat, ppfd );
547         release_dc_ptr( dc );
548     }
549     return bRet;
550 }
551
552
553 /******************************************************************************
554  * GetPixelFormat [GDI32.@]
555  * Gets index of pixel format of DC
556  *
557  * PARAMETERS
558  *    hdc [I] Device context whose pixel format index is sought
559  *
560  * RETURNS
561  *    Success: Currently selected pixel format
562  *    Failure: 0
563  */
564 INT WINAPI GetPixelFormat( HDC hdc )
565 {
566     INT ret = 0;
567     DC * dc = get_dc_ptr( hdc );
568
569     TRACE("(%p)\n",hdc);
570
571     if (dc)
572     {
573         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixelFormat );
574         update_dc( dc );
575         ret = physdev->funcs->pGetPixelFormat( physdev );
576         release_dc_ptr( dc );
577     }
578     return ret;
579 }
580
581
582 /******************************************************************************
583  * DescribePixelFormat [GDI32.@]
584  * Gets info about pixel format from DC
585  *
586  * PARAMS
587  *    hdc          [I] Device context
588  *    iPixelFormat [I] Pixel format selector
589  *    nBytes       [I] Size of buffer
590  *    ppfd         [O] Pointer to structure to receive pixel format data
591  *
592  * RETURNS
593  *    Success: Maximum pixel format index of the device context
594  *    Failure: 0
595  */
596 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
597                                 LPPIXELFORMATDESCRIPTOR ppfd )
598 {
599     INT ret = 0;
600     DC * dc = get_dc_ptr( hdc );
601
602     TRACE("(%p,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
603
604     if (dc)
605     {
606         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pDescribePixelFormat );
607         update_dc( dc );
608         ret = physdev->funcs->pDescribePixelFormat( physdev, iPixelFormat, nBytes, ppfd );
609         release_dc_ptr( dc );
610     }
611     return ret;
612 }
613
614
615 /******************************************************************************
616  * SwapBuffers [GDI32.@]
617  * Exchanges front and back buffers of window
618  *
619  * PARAMS
620  *    hdc [I] Device context whose buffers get swapped
621  *
622  * RETURNS
623  *    Success: TRUE
624  *    Failure: FALSE
625  */
626 BOOL WINAPI SwapBuffers( HDC hdc )
627 {
628     INT bRet = FALSE;
629     DC * dc = get_dc_ptr( hdc );
630
631     TRACE("(%p)\n",hdc);
632
633     if (dc)
634     {
635         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSwapBuffers );
636         update_dc( dc );
637         bRet = physdev->funcs->pSwapBuffers( physdev );
638         release_dc_ptr( dc );
639     }
640     return bRet;
641 }
642
643
644 /***********************************************************************
645  *           PaintRgn    (GDI32.@)
646  */
647 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
648 {
649     BOOL ret = FALSE;
650     DC * dc = get_dc_ptr( hdc );
651
652     if (dc)
653     {
654         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
655         update_dc( dc );
656         ret = physdev->funcs->pPaintRgn( physdev, hrgn );
657         release_dc_ptr( dc );
658     }
659     return ret;
660 }
661
662
663 /***********************************************************************
664  *           FillRgn    (GDI32.@)
665  */
666 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
667 {
668     BOOL retval = FALSE;
669     DC * dc = get_dc_ptr( hdc );
670
671     if (dc)
672     {
673         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillRgn );
674         update_dc( dc );
675         retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
676         release_dc_ptr( dc );
677     }
678     return retval;
679 }
680
681
682 /***********************************************************************
683  *           FrameRgn     (GDI32.@)
684  */
685 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
686                           INT nWidth, INT nHeight )
687 {
688     BOOL ret = FALSE;
689     DC *dc = get_dc_ptr( hdc );
690
691     if (dc)
692     {
693         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
694         update_dc( dc );
695         ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
696         release_dc_ptr( dc );
697     }
698     return ret;
699 }
700
701
702 /***********************************************************************
703  *           InvertRgn    (GDI32.@)
704  */
705 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
706 {
707     BOOL ret = FALSE;
708     DC *dc = get_dc_ptr( hdc );
709
710     if (dc)
711     {
712         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
713         update_dc( dc );
714         ret = physdev->funcs->pInvertRgn( physdev, hrgn );
715         release_dc_ptr( dc );
716     }
717     return ret;
718 }
719
720
721 /**********************************************************************
722  *          Polyline   (GDI32.@)
723  */
724 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
725 {
726     BOOL ret = FALSE;
727     DC * dc = get_dc_ptr( hdc );
728
729     if (dc)
730     {
731         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyline );
732         update_dc( dc );
733         ret = physdev->funcs->pPolyline( physdev, pt, count );
734         release_dc_ptr( dc );
735     }
736     return ret;
737 }
738
739 /**********************************************************************
740  *          PolylineTo   (GDI32.@)
741  */
742 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
743 {
744     DC * dc = get_dc_ptr( hdc );
745     PHYSDEV physdev;
746     BOOL ret;
747
748     if(!dc) return FALSE;
749
750     update_dc( dc );
751     physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
752     ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
753
754     if (ret && cCount)
755     {
756         dc->CursPosX = pt[cCount-1].x;
757         dc->CursPosY = pt[cCount-1].y;
758     }
759     release_dc_ptr( dc );
760     return ret;
761 }
762
763
764 /**********************************************************************
765  *          Polygon  (GDI32.@)
766  */
767 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
768 {
769     BOOL ret = FALSE;
770     DC * dc = get_dc_ptr( hdc );
771
772     if (dc)
773     {
774         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolygon );
775         update_dc( dc );
776         ret = physdev->funcs->pPolygon( physdev, pt, count );
777         release_dc_ptr( dc );
778     }
779     return ret;
780 }
781
782
783 /**********************************************************************
784  *          PolyPolygon  (GDI32.@)
785  */
786 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
787                              UINT polygons )
788 {
789     BOOL ret = FALSE;
790     DC * dc = get_dc_ptr( hdc );
791
792     if (dc)
793     {
794         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
795         update_dc( dc );
796         ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
797         release_dc_ptr( dc );
798     }
799     return ret;
800 }
801
802 /**********************************************************************
803  *          PolyPolyline  (GDI32.@)
804  */
805 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
806                             DWORD polylines )
807 {
808     BOOL ret = FALSE;
809     DC * dc = get_dc_ptr( hdc );
810
811     if (dc)
812     {
813         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
814         update_dc( dc );
815         ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
816         release_dc_ptr( dc );
817     }
818     return ret;
819 }
820
821 /**********************************************************************
822  *          ExtFloodFill   (GDI32.@)
823  */
824 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
825                               UINT fillType )
826 {
827     BOOL ret = FALSE;
828     DC * dc = get_dc_ptr( hdc );
829
830     if (dc)
831     {
832         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );
833
834         update_dc( dc );
835         ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
836         release_dc_ptr( dc );
837     }
838     return ret;
839 }
840
841
842 /**********************************************************************
843  *          FloodFill   (GDI32.@)
844  */
845 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
846 {
847     return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
848 }
849
850
851 /******************************************************************************
852  * PolyBezier [GDI32.@]
853  * Draws one or more Bezier curves
854  *
855  * PARAMS
856  *    hDc     [I] Handle to device context
857  *    lppt    [I] Pointer to endpoints and control points
858  *    cPoints [I] Count of endpoints and control points
859  *
860  * RETURNS
861  *    Success: TRUE
862  *    Failure: FALSE
863  */
864 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
865 {
866     PHYSDEV physdev;
867     BOOL ret;
868     DC * dc;
869
870     /* cPoints must be 3 * n + 1 (where n>=1) */
871     if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
872
873     dc = get_dc_ptr( hdc );
874     if(!dc) return FALSE;
875
876     update_dc( dc );
877     physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
878     ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
879     release_dc_ptr( dc );
880     return ret;
881 }
882
883 /******************************************************************************
884  * PolyBezierTo [GDI32.@]
885  * Draws one or more Bezier curves
886  *
887  * PARAMS
888  *    hDc     [I] Handle to device context
889  *    lppt    [I] Pointer to endpoints and control points
890  *    cPoints [I] Count of endpoints and control points
891  *
892  * RETURNS
893  *    Success: TRUE
894  *    Failure: FALSE
895  */
896 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
897 {
898     DC * dc;
899     BOOL ret;
900     PHYSDEV physdev;
901
902     /* cbPoints must be 3 * n (where n>=1) */
903     if (!cPoints || (cPoints % 3) != 0) return FALSE;
904
905     dc = get_dc_ptr( hdc );
906     if(!dc) return FALSE;
907
908     update_dc( dc );
909     physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
910     ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
911
912     if(ret) {
913         dc->CursPosX = lppt[cPoints-1].x;
914         dc->CursPosY = lppt[cPoints-1].y;
915     }
916     release_dc_ptr( dc );
917     return ret;
918 }
919
920 /***********************************************************************
921  *      AngleArc (GDI32.@)
922  */
923 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
924 {
925     PHYSDEV physdev;
926     BOOL result;
927     DC *dc;
928
929     if( (signed int)dwRadius < 0 )
930         return FALSE;
931
932     dc = get_dc_ptr( hdc );
933     if(!dc) return FALSE;
934
935     update_dc( dc );
936     physdev = GET_DC_PHYSDEV( dc, pAngleArc );
937     result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
938
939     if (result) {
940         dc->CursPosX = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
941         dc->CursPosY = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
942     }
943     release_dc_ptr( dc );
944     return result;
945 }
946
947 /***********************************************************************
948  *      PolyDraw (GDI32.@)
949  */
950 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
951                        DWORD cCount)
952 {
953     DC *dc = get_dc_ptr( hdc );
954     PHYSDEV physdev;
955     BOOL result;
956
957     if(!dc) return FALSE;
958
959     update_dc( dc );
960     physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
961     result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
962     release_dc_ptr( dc );
963     return result;
964 }
965
966
967 /**********************************************************************
968  *           LineDDA   (GDI32.@)
969  */
970 BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
971                     LINEDDAPROC callback, LPARAM lParam )
972 {
973     INT xadd = 1, yadd = 1;
974     INT err,erradd;
975     INT cnt;
976     INT dx = nXEnd - nXStart;
977     INT dy = nYEnd - nYStart;
978
979     if (dx < 0)
980     {
981         dx = -dx;
982         xadd = -1;
983     }
984     if (dy < 0)
985     {
986         dy = -dy;
987         yadd = -1;
988     }
989     if (dx > dy)  /* line is "more horizontal" */
990     {
991         err = 2*dy - dx; erradd = 2*dy - 2*dx;
992         for(cnt = 0;cnt < dx; cnt++)
993         {
994             callback(nXStart,nYStart,lParam);
995             if (err > 0)
996             {
997                 nYStart += yadd;
998                 err += erradd;
999             }
1000             else err += 2*dy;
1001             nXStart += xadd;
1002         }
1003     }
1004     else   /* line is "more vertical" */
1005     {
1006         err = 2*dx - dy; erradd = 2*dx - 2*dy;
1007         for(cnt = 0;cnt < dy; cnt++)
1008         {
1009             callback(nXStart,nYStart,lParam);
1010             if (err > 0)
1011             {
1012                 nXStart += xadd;
1013                 err += erradd;
1014             }
1015             else err += 2*dx;
1016             nYStart += yadd;
1017         }
1018     }
1019     return TRUE;
1020 }
1021
1022
1023 /******************************************************************
1024  *
1025  *   *Very* simple bezier drawing code,
1026  *
1027  *   It uses a recursive algorithm to divide the curve in a series
1028  *   of straight line segments. Not ideal but sufficient for me.
1029  *   If you are in need for something better look for some incremental
1030  *   algorithm.
1031  *
1032  *   7 July 1998 Rein Klazes
1033  */
1034
1035  /*
1036   * some macro definitions for bezier drawing
1037   *
1038   * to avoid truncation errors the coordinates are
1039   * shifted upwards. When used in drawing they are
1040   * shifted down again, including correct rounding
1041   * and avoiding floating point arithmetic
1042   * 4 bits should allow 27 bits coordinates which I saw
1043   * somewhere in the win32 doc's
1044   *
1045   */
1046
1047 #define BEZIERSHIFTBITS 4
1048 #define BEZIERSHIFTUP(x)    ((x)<<BEZIERSHIFTBITS)
1049 #define BEZIERPIXEL        BEZIERSHIFTUP(1)
1050 #define BEZIERSHIFTDOWN(x)  (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1051 /* maximum depth of recursion */
1052 #define BEZIERMAXDEPTH  8
1053
1054 /* size of array to store points on */
1055 /* enough for one curve */
1056 #define BEZIER_INITBUFSIZE    (150)
1057
1058 /* calculate Bezier average, in this case the middle
1059  * correctly rounded...
1060  * */
1061
1062 #define BEZIERMIDDLE(Mid, P1, P2) \
1063     (Mid).x=((P1).x+(P2).x + 1)/2;\
1064     (Mid).y=((P1).y+(P2).y + 1)/2;
1065
1066 /**********************************************************
1067 * BezierCheck helper function to check
1068 * that recursion can be terminated
1069 *       Points[0] and Points[3] are begin and endpoint
1070 *       Points[1] and Points[2] are control points
1071 *       level is the recursion depth
1072 *       returns true if the recursion can be terminated
1073 */
1074 static BOOL BezierCheck( int level, POINT *Points)
1075 {
1076     INT dx, dy;
1077     dx=Points[3].x-Points[0].x;
1078     dy=Points[3].y-Points[0].y;
1079     if(abs(dy)<=abs(dx)){/* shallow line */
1080         /* check that control points are between begin and end */
1081         if(Points[1].x < Points[0].x){
1082             if(Points[1].x < Points[3].x)
1083                 return FALSE;
1084         }else
1085             if(Points[1].x > Points[3].x)
1086                 return FALSE;
1087         if(Points[2].x < Points[0].x){
1088             if(Points[2].x < Points[3].x)
1089                 return FALSE;
1090         }else
1091             if(Points[2].x > Points[3].x)
1092                 return FALSE;
1093         dx=BEZIERSHIFTDOWN(dx);
1094         if(!dx) return TRUE;
1095         if(abs(Points[1].y-Points[0].y-(dy/dx)*
1096                 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1097            abs(Points[2].y-Points[0].y-(dy/dx)*
1098                    BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1099             return FALSE;
1100         else
1101             return TRUE;
1102     }else{ /* steep line */
1103         /* check that control points are between begin and end */
1104         if(Points[1].y < Points[0].y){
1105             if(Points[1].y < Points[3].y)
1106                 return FALSE;
1107         }else
1108             if(Points[1].y > Points[3].y)
1109                 return FALSE;
1110         if(Points[2].y < Points[0].y){
1111             if(Points[2].y < Points[3].y)
1112                 return FALSE;
1113         }else
1114             if(Points[2].y > Points[3].y)
1115                 return FALSE;
1116         dy=BEZIERSHIFTDOWN(dy);
1117         if(!dy) return TRUE;
1118         if(abs(Points[1].x-Points[0].x-(dx/dy)*
1119                 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1120            abs(Points[2].x-Points[0].x-(dx/dy)*
1121                    BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1122             return FALSE;
1123         else
1124             return TRUE;
1125     }
1126 }
1127
1128 /* Helper for GDI_Bezier.
1129  * Just handles one Bezier, so Points should point to four POINTs
1130  */
1131 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1132                                 INT *nPtsOut, INT level )
1133 {
1134     if(*nPtsOut == *dwOut) {
1135         *dwOut *= 2;
1136         *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1137                                *dwOut * sizeof(POINT) );
1138     }
1139
1140     if(!level || BezierCheck(level, Points)) {
1141         if(*nPtsOut == 0) {
1142             (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1143             (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1144             *nPtsOut = 1;
1145         }
1146         (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1147         (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1148         (*nPtsOut) ++;
1149     } else {
1150         POINT Points2[4]; /* for the second recursive call */
1151         Points2[3]=Points[3];
1152         BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1153         BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1154         BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1155
1156         BEZIERMIDDLE(Points[1], Points[0],  Points[1]);
1157         BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1158         BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1159
1160         Points2[0]=Points[3];
1161
1162         /* do the two halves */
1163         GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1164         GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1165     }
1166 }
1167
1168
1169
1170 /***********************************************************************
1171  *           GDI_Bezier   [INTERNAL]
1172  *   Calculate line segments that approximate -what microsoft calls- a bezier
1173  *   curve.
1174  *   The routine recursively divides the curve in two parts until a straight
1175  *   line can be drawn
1176  *
1177  *  PARAMS
1178  *
1179  *  Points  [I] Ptr to count POINTs which are the end and control points
1180  *              of the set of Bezier curves to flatten.
1181  *  count   [I] Number of Points.  Must be 3n+1.
1182  *  nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1183  *              lines+1).
1184  *
1185  *  RETURNS
1186  *
1187  *  Ptr to an array of POINTs that contain the lines that approximate the
1188  *  Beziers.  The array is allocated on the process heap and it is the caller's
1189  *  responsibility to HeapFree it. [this is not a particularly nice interface
1190  *  but since we can't know in advance how many points we will generate, the
1191  *  alternative would be to call the function twice, once to determine the size
1192  *  and a second time to do the work - I decided this was too much of a pain].
1193  */
1194 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1195 {
1196     POINT *out;
1197     INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1198
1199     if (count == 1 || (count - 1) % 3 != 0) {
1200         ERR("Invalid no. of points %d\n", count);
1201         return NULL;
1202     }
1203     *nPtsOut = 0;
1204     out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1205     for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1206         POINT ptBuf[4];
1207         memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1208         for(i = 0; i < 4; i++) {
1209             ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1210             ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1211         }
1212         GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1213     }
1214     TRACE("Produced %d points\n", *nPtsOut);
1215     return out;
1216 }
1217
1218 /******************************************************************************
1219  *           GdiGradientFill   (GDI32.@)
1220  *
1221  *  FIXME: we don't support the Alpha channel properly
1222  */
1223 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1224                           void * grad_array, ULONG ngrad, ULONG mode )
1225 {
1226   unsigned int i;
1227
1228   TRACE("vert_array:%p nvert:%d grad_array:%p ngrad:%d\n",
1229         vert_array, nvert, grad_array, ngrad);
1230
1231   switch(mode) 
1232     {
1233     case GRADIENT_FILL_RECT_H:
1234       for(i = 0; i < ngrad; i++) 
1235         {
1236           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1237           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1238           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1239           int y1 = v1->y < v2->y ? v1->y : v2->y;
1240           int y2 = v2->y > v1->y ? v2->y : v1->y;
1241           int x, dx;
1242           if (v1->x > v2->x)
1243             {
1244               TRIVERTEX *t = v2;
1245               v2 = v1;
1246               v1 = t;
1247             }
1248           dx = v2->x - v1->x;
1249           for (x = 0; x < dx; x++)
1250             {
1251               POINT pts[2];
1252               HPEN hPen, hOldPen;
1253               
1254               hPen = CreatePen( PS_SOLID, 1, RGB(
1255                   (v1->Red   * (dx - x) + v2->Red   * x) / dx >> 8,
1256                   (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
1257                   (v1->Blue  * (dx - x) + v2->Blue  * x) / dx >> 8));
1258               hOldPen = SelectObject( hdc, hPen );
1259               pts[0].x = v1->x + x;
1260               pts[0].y = y1;
1261               pts[1].x = v1->x + x;
1262               pts[1].y = y2;
1263               Polyline( hdc, &pts[0], 2 );
1264               DeleteObject( SelectObject(hdc, hOldPen ) );
1265             }
1266         }
1267       break;
1268     case GRADIENT_FILL_RECT_V:
1269       for(i = 0; i < ngrad; i++) 
1270         {
1271           GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
1272           TRIVERTEX *v1 = vert_array + rect->UpperLeft;
1273           TRIVERTEX *v2 = vert_array + rect->LowerRight;
1274           int x1 = v1->x < v2->x ? v1->x : v2->x;
1275           int x2 = v2->x > v1->x ? v2->x : v1->x;
1276           int y, dy;
1277           if (v1->y > v2->y)
1278             {
1279               TRIVERTEX *t = v2;
1280               v2 = v1;
1281               v1 = t;
1282             }
1283           dy = v2->y - v1->y;
1284           for (y = 0; y < dy; y++)
1285             {
1286               POINT pts[2];
1287               HPEN hPen, hOldPen;
1288               
1289               hPen = CreatePen( PS_SOLID, 1, RGB(
1290                   (v1->Red   * (dy - y) + v2->Red   * y) / dy >> 8,
1291                   (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
1292                   (v1->Blue  * (dy - y) + v2->Blue  * y) / dy >> 8));
1293               hOldPen = SelectObject( hdc, hPen );
1294               pts[0].x = x1;
1295               pts[0].y = v1->y + y;
1296               pts[1].x = x2;
1297               pts[1].y = v1->y + y;
1298               Polyline( hdc, &pts[0], 2 );
1299               DeleteObject( SelectObject(hdc, hOldPen ) );
1300             }
1301         }
1302       break;
1303     case GRADIENT_FILL_TRIANGLE:
1304       for (i = 0; i < ngrad; i++)  
1305         {
1306           GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
1307           TRIVERTEX *v1 = vert_array + tri->Vertex1;
1308           TRIVERTEX *v2 = vert_array + tri->Vertex2;
1309           TRIVERTEX *v3 = vert_array + tri->Vertex3;
1310           int y, dy;
1311           
1312           if (v1->y > v2->y)
1313             { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
1314           if (v2->y > v3->y)
1315             {
1316               TRIVERTEX *t = v2; v2 = v3; v3 = t;
1317               if (v1->y > v2->y)
1318                 { t = v1; v1 = v2; v2 = t; }
1319             }
1320           /* v1->y <= v2->y <= v3->y */
1321
1322           dy = v3->y - v1->y;
1323           for (y = 0; y < dy; y++)
1324             {
1325               /* v1->y <= y < v3->y */
1326               TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
1327               /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
1328               int dy2 = v2->y - v->y;
1329               int y2 = y + v1->y - v->y;
1330
1331               int x1 = (v3->x     * y  + v1->x     * (dy  - y )) / dy;
1332               int x2 = (v2->x     * y2 + v-> x     * (dy2 - y2)) / dy2;
1333               int r1 = (v3->Red   * y  + v1->Red   * (dy  - y )) / dy;
1334               int r2 = (v2->Red   * y2 + v-> Red   * (dy2 - y2)) / dy2;
1335               int g1 = (v3->Green * y  + v1->Green * (dy  - y )) / dy;
1336               int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
1337               int b1 = (v3->Blue  * y  + v1->Blue  * (dy  - y )) / dy;
1338               int b2 = (v2->Blue  * y2 + v-> Blue  * (dy2 - y2)) / dy2;
1339                
1340               int x;
1341               if (x1 < x2)
1342                 {
1343                   int dx = x2 - x1;
1344                   for (x = 0; x < dx; x++)
1345                     SetPixel (hdc, x + x1, y + v1->y, RGB(
1346                       (r1 * (dx - x) + r2 * x) / dx >> 8,
1347                       (g1 * (dx - x) + g2 * x) / dx >> 8,
1348                       (b1 * (dx - x) + b2 * x) / dx >> 8));
1349                 }
1350               else
1351                 {
1352                   int dx = x1 - x2;
1353                   for (x = 0; x < dx; x++)
1354                     SetPixel (hdc, x + x2, y + v1->y, RGB(
1355                       (r2 * (dx - x) + r1 * x) / dx >> 8,
1356                       (g2 * (dx - x) + g1 * x) / dx >> 8,
1357                       (b2 * (dx - x) + b1 * x) / dx >> 8));
1358                 }
1359             }
1360         }
1361       break;
1362     default:
1363       return FALSE;
1364   }
1365
1366   return TRUE;
1367 }
1368
1369 /******************************************************************************
1370  *           GdiDrawStream   (GDI32.@)
1371  *
1372  */
1373 BOOL WINAPI GdiDrawStream( HDC hdc, ULONG in, void * pvin )
1374 {
1375     FIXME("stub: %p, %d, %p\n", hdc, in, pvin);
1376     return FALSE;
1377 }