Fixed a few compilation warnings
[wine/multimedia.git] / graphics / painting.c
blobd7c0626337c026be3b2f3b70155e9978a74c8145
1 /*
2 * GDI drawing functions.
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
6 * 1999 Huw D M Davies
7 */
9 #include <string.h>
10 #include "dc.h"
11 #include "bitmap.h"
12 #include "heap.h"
13 #include "region.h"
14 #include "path.h"
15 #include "debugtools.h"
16 #include "winerror.h"
17 #include "windef.h"
18 #include "wingdi.h"
20 DEFAULT_DEBUG_CHANNEL(gdi);
23 /***********************************************************************
24 * LineTo16 (GDI.19)
26 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
28 return LineTo( hdc, x, y );
32 /***********************************************************************
33 * LineTo (GDI32.249)
35 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
37 DC * dc = DC_GetDCUpdate( hdc );
38 BOOL ret;
40 if(!dc) return FALSE;
42 if(PATH_IsPathOpen(dc->w.path))
43 ret = PATH_LineTo(dc, x, y);
44 else
45 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc,x,y);
46 if(ret) {
47 dc->w.CursPosX = x;
48 dc->w.CursPosY = y;
50 GDI_ReleaseObj( hdc );
51 return ret;
55 /***********************************************************************
56 * MoveTo16 (GDI.20)
58 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
60 POINT16 pt;
62 if (!MoveToEx16(hdc,x,y,&pt))
63 return 0;
64 return MAKELONG(pt.x,pt.y);
68 /***********************************************************************
69 * MoveToEx16 (GDI.483)
71 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
73 POINT pt32;
75 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
76 if (pt) CONV_POINT32TO16( &pt32, pt );
77 return TRUE;
82 /***********************************************************************
83 * MoveToEx (GDI32.254)
85 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
87 BOOL ret = TRUE;
88 DC * dc = DC_GetDCUpdate( hdc );
90 if(!dc) return FALSE;
92 if(pt) {
93 pt->x = dc->w.CursPosX;
94 pt->y = dc->w.CursPosY;
96 dc->w.CursPosX = x;
97 dc->w.CursPosY = y;
99 if(PATH_IsPathOpen(dc->w.path)) ret = PATH_MoveTo(dc);
100 else if (dc->funcs->pMoveToEx) ret = dc->funcs->pMoveToEx(dc,x,y,pt);
101 GDI_ReleaseObj( hdc );
102 return ret;
106 /***********************************************************************
107 * Arc16 (GDI.23)
109 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
110 INT16 bottom, INT16 xstart, INT16 ystart,
111 INT16 xend, INT16 yend )
113 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
114 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
115 (INT)yend );
119 /***********************************************************************
120 * Arc (GDI32.7)
122 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
123 INT bottom, INT xstart, INT ystart,
124 INT xend, INT yend )
126 BOOL ret = FALSE;
127 DC * dc = DC_GetDCUpdate( hdc );
128 if (dc)
130 if(PATH_IsPathOpen(dc->w.path))
131 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend);
132 else if (dc->funcs->pArc)
133 ret = dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
134 GDI_ReleaseObj( hdc );
136 return ret;
139 /***********************************************************************
140 * ArcTo (GDI32.8)
142 BOOL WINAPI ArcTo( HDC hdc,
143 INT left, INT top,
144 INT right, INT bottom,
145 INT xstart, INT ystart,
146 INT xend, INT yend )
148 BOOL result;
149 DC * dc = DC_GetDCUpdate( hdc );
150 if(!dc) return FALSE;
152 if(dc->funcs->pArcTo)
154 result = dc->funcs->pArcTo( dc, left, top, right, bottom,
155 xstart, ystart, xend, yend );
156 GDI_ReleaseObj( hdc );
157 return result;
159 GDI_ReleaseObj( hdc );
161 * Else emulate it.
162 * According to the documentation, a line is drawn from the current
163 * position to the starting point of the arc.
165 LineTo(hdc, xstart, ystart);
167 * Then the arc is drawn.
169 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
171 * If no error occured, the current position is moved to the ending
172 * point of the arc.
174 if (result) MoveToEx(hdc, xend, yend, NULL);
175 return result;
178 /***********************************************************************
179 * Pie16 (GDI.26)
181 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
182 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
183 INT16 xend, INT16 yend )
185 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
186 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
187 (INT)yend );
191 /***********************************************************************
192 * Pie (GDI32.262)
194 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
195 INT right, INT bottom, INT xstart, INT ystart,
196 INT xend, INT yend )
198 BOOL ret = FALSE;
199 DC * dc = DC_GetDCUpdate( hdc );
200 if (dc)
202 if (PATH_IsPathOpen(dc->w.path))
203 FIXME("-> Path: stub\n");
204 else if (dc->funcs->pPie)
205 ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
206 GDI_ReleaseObj( hdc );
208 return ret;
212 /***********************************************************************
213 * Chord16 (GDI.348)
215 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
216 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
217 INT16 xend, INT16 yend )
219 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
223 /***********************************************************************
224 * Chord (GDI32.14)
226 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
227 INT right, INT bottom, INT xstart, INT ystart,
228 INT xend, INT yend )
230 BOOL ret = FALSE;
231 DC * dc = DC_GetDCUpdate( hdc );
232 if (dc)
234 if(PATH_IsPathOpen(dc->w.path))
235 FIXME("-> Path: stub\n");
236 else if (dc->funcs->pChord)
237 ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
238 GDI_ReleaseObj( hdc );
240 return ret;
244 /***********************************************************************
245 * Ellipse16 (GDI.24)
247 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
248 INT16 right, INT16 bottom )
250 return Ellipse( hdc, left, top, right, bottom );
254 /***********************************************************************
255 * Ellipse (GDI32.75)
257 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
258 INT right, INT bottom )
260 BOOL ret = FALSE;
261 DC * dc = DC_GetDCUpdate( hdc );
262 if (dc)
264 if(PATH_IsPathOpen(dc->w.path))
265 FIXME("-> Path: stub\n");
266 else if (dc->funcs->pEllipse)
267 ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
268 GDI_ReleaseObj( hdc );
270 return ret;
274 /***********************************************************************
275 * Rectangle16 (GDI.27)
277 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
278 INT16 right, INT16 bottom )
280 return Rectangle( hdc, left, top, right, bottom );
284 /***********************************************************************
285 * Rectangle (GDI32.283)
287 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
288 INT right, INT bottom )
290 BOOL ret = FALSE;
291 DC * dc = DC_GetDCUpdate( hdc );
292 if (dc)
294 if(PATH_IsPathOpen(dc->w.path))
295 ret = PATH_Rectangle(dc, left, top, right, bottom);
296 else if (dc->funcs->pRectangle)
297 ret = dc->funcs->pRectangle(dc,left,top,right,bottom);
298 GDI_ReleaseObj( hdc );
300 return ret;
304 /***********************************************************************
305 * RoundRect16 (GDI.28)
307 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
308 INT16 bottom, INT16 ell_width, INT16 ell_height )
310 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
314 /***********************************************************************
315 * RoundRect (GDI32.291)
317 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
318 INT bottom, INT ell_width, INT ell_height )
320 BOOL ret = FALSE;
321 DC *dc = DC_GetDCUpdate( hdc );
323 if (dc)
325 if(PATH_IsPathOpen(dc->w.path))
326 FIXME("-> Path: stub\n");
327 else if (dc->funcs->pRoundRect)
328 ret = dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
329 GDI_ReleaseObj( hdc );
331 return ret;
334 /***********************************************************************
335 * SetPixel16 (GDI.31)
337 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
339 return SetPixel( hdc, x, y, color );
343 /***********************************************************************
344 * SetPixel (GDI32.327)
346 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
348 COLORREF ret = 0;
349 DC * dc = DC_GetDCUpdate( hdc );
350 if (dc)
352 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc,x,y,color);
353 GDI_ReleaseObj( hdc );
355 return ret;
358 /***********************************************************************
359 * SetPixelV (GDI32.329)
361 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
363 BOOL ret = FALSE;
364 DC * dc = DC_GetDCUpdate( hdc );
365 if (dc)
367 if (dc->funcs->pSetPixel)
369 dc->funcs->pSetPixel(dc,x,y,color);
370 ret = TRUE;
372 GDI_ReleaseObj( hdc );
374 return ret;
377 /***********************************************************************
378 * GetPixel16 (GDI.83)
380 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
382 return GetPixel( hdc, x, y );
386 /***********************************************************************
387 * GetPixel (GDI32.211)
389 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
391 COLORREF ret = 0;
392 DC * dc = DC_GetDCUpdate( hdc );
394 if (dc)
396 /* FIXME: should this be in the graphics driver? */
397 if (PtVisible( hdc, x, y ))
399 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc,x,y);
401 GDI_ReleaseObj( hdc );
403 return ret;
407 /******************************************************************************
408 * ChoosePixelFormat [GDI32.13]
409 * Matches a pixel format to given format
411 * PARAMS
412 * hdc [I] Device context to search for best pixel match
413 * ppfd [I] Pixel format for which a match is sought
415 * RETURNS
416 * Success: Pixel format index closest to given format
417 * Failure: 0
419 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
421 INT ret = 0;
422 DC * dc = DC_GetDCPtr( hdc );
424 TRACE("(%08x,%p)\n",hdc,ppfd);
426 if (!dc) return 0;
428 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
429 else ret = dc->funcs->pChoosePixelFormat(dc,ppfd);
431 GDI_ReleaseObj( hdc );
432 return ret;
436 /******************************************************************************
437 * SetPixelFormat [GDI32.328]
438 * Sets pixel format of device context
440 * PARAMS
441 * hdc [I] Device context to search for best pixel match
442 * iPixelFormat [I] Pixel format index
443 * ppfd [I] Pixel format for which a match is sought
445 * RETURNS STD
447 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
448 const PIXELFORMATDESCRIPTOR *ppfd)
450 INT bRet = FALSE;
451 DC * dc = DC_GetDCPtr( hdc );
453 TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
455 if (!dc) return 0;
457 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
458 else bRet = dc->funcs->pSetPixelFormat(dc,iPixelFormat,ppfd);
460 GDI_ReleaseObj( hdc );
461 return bRet;
465 /******************************************************************************
466 * GetPixelFormat [GDI32.212]
467 * Gets index of pixel format of DC
469 * PARAMETERS
470 * hdc [I] Device context whose pixel format index is sought
472 * RETURNS
473 * Success: Currently selected pixel format
474 * Failure: 0
476 INT WINAPI GetPixelFormat( HDC hdc )
478 INT ret = 0;
479 DC * dc = DC_GetDCPtr( hdc );
481 TRACE("(%08x)\n",hdc);
483 if (!dc) return 0;
485 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
486 else ret = dc->funcs->pGetPixelFormat(dc);
488 GDI_ReleaseObj( hdc );
489 return ret;
493 /******************************************************************************
494 * DescribePixelFormat [GDI32.71]
495 * Gets info about pixel format from DC
497 * PARAMS
498 * hdc [I] Device context
499 * iPixelFormat [I] Pixel format selector
500 * nBytes [I] Size of buffer
501 * ppfd [O] Pointer to structure to receive pixel format data
503 * RETURNS
504 * Success: Maximum pixel format index of the device context
505 * Failure: 0
507 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
508 LPPIXELFORMATDESCRIPTOR ppfd )
510 INT ret = 0;
511 DC * dc = DC_GetDCPtr( hdc );
513 TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
515 if (!dc) return 0;
517 if (!dc->funcs->pDescribePixelFormat)
519 FIXME(" :stub\n");
520 ppfd->nSize = nBytes;
521 ppfd->nVersion = 1;
522 ret = 3;
524 else ret = dc->funcs->pDescribePixelFormat(dc,iPixelFormat,nBytes,ppfd);
526 GDI_ReleaseObj( hdc );
527 return ret;
531 /******************************************************************************
532 * SwapBuffers [GDI32.354]
533 * Exchanges front and back buffers of window
535 * PARAMS
536 * hdc [I] Device context whose buffers get swapped
538 * RETURNS STD
540 BOOL WINAPI SwapBuffers( HDC hdc )
542 INT bRet = FALSE;
543 DC * dc = DC_GetDCPtr( hdc );
545 TRACE("(%08x)\n",hdc);
547 if (!dc) return TRUE;
549 if (!dc->funcs->pSwapBuffers)
551 FIXME(" :stub\n");
552 bRet = TRUE;
554 else bRet = dc->funcs->pSwapBuffers(dc);
556 GDI_ReleaseObj( hdc );
557 return bRet;
561 /***********************************************************************
562 * PaintRgn16 (GDI.43)
564 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
566 return PaintRgn( hdc, hrgn );
570 /***********************************************************************
571 * PaintRgn (GDI32.259)
573 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
575 BOOL ret = FALSE;
576 DC * dc = DC_GetDCUpdate( hdc );
577 if (dc)
579 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc,hrgn);
580 GDI_ReleaseObj( hdc );
582 return ret;
586 /***********************************************************************
587 * FillRgn16 (GDI.40)
589 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
591 return FillRgn( hdc, hrgn, hbrush );
595 /***********************************************************************
596 * FillRgn (GDI32.101)
598 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
600 BOOL retval = FALSE;
601 HBRUSH prevBrush;
602 DC * dc = DC_GetDCUpdate( hdc );
604 if (!dc) return FALSE;
605 if(dc->funcs->pFillRgn)
606 retval = dc->funcs->pFillRgn(dc, hrgn, hbrush);
607 else if ((prevBrush = SelectObject( hdc, hbrush )))
609 retval = PaintRgn( hdc, hrgn );
610 SelectObject( hdc, prevBrush );
612 GDI_ReleaseObj( hdc );
613 return retval;
617 /***********************************************************************
618 * FrameRgn16 (GDI.41)
620 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
621 INT16 nWidth, INT16 nHeight )
623 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
627 /***********************************************************************
628 * FrameRgn (GDI32.105)
630 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
631 INT nWidth, INT nHeight )
633 BOOL ret = FALSE;
634 DC *dc = DC_GetDCUpdate( hdc );
636 if (!dc) return FALSE;
637 if(dc->funcs->pFrameRgn)
638 ret = dc->funcs->pFrameRgn( dc, hrgn, hbrush, nWidth, nHeight );
639 else
641 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
642 if (tmp)
644 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
646 FillRgn( hdc, tmp, hbrush );
647 ret = TRUE;
649 DeleteObject( tmp );
652 GDI_ReleaseObj( hdc );
653 return ret;
657 /***********************************************************************
658 * InvertRgn16 (GDI.42)
660 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
662 return InvertRgn( hdc, hrgn );
666 /***********************************************************************
667 * InvertRgn (GDI32.246)
669 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
671 HBRUSH prevBrush;
672 INT prevROP;
673 BOOL retval;
674 DC *dc = DC_GetDCUpdate( hdc );
675 if (!dc) return FALSE;
677 if(dc->funcs->pInvertRgn)
678 retval = dc->funcs->pInvertRgn( dc, hrgn );
679 else
681 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
682 prevROP = SetROP2( hdc, R2_NOT );
683 retval = PaintRgn( hdc, hrgn );
684 SelectObject( hdc, prevBrush );
685 SetROP2( hdc, prevROP );
687 GDI_ReleaseObj( hdc );
688 return retval;
691 /**********************************************************************
692 * Polyline16 (GDI.37)
694 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
696 register int i;
697 BOOL16 ret;
698 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
699 count*sizeof(POINT) );
701 if (!pt32) return FALSE;
702 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
703 ret = Polyline(hdc,pt32,count);
704 HeapFree( GetProcessHeap(), 0, pt32 );
705 return ret;
709 /**********************************************************************
710 * Polyline (GDI32.276)
712 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
714 BOOL ret = FALSE;
715 DC * dc = DC_GetDCUpdate( hdc );
716 if (dc)
718 if (PATH_IsPathOpen(dc->w.path)) ret = PATH_Polyline(dc, pt, count);
719 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc,pt,count);
720 GDI_ReleaseObj( hdc );
722 return ret;
725 /**********************************************************************
726 * PolylineTo (GDI32.277)
728 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
730 DC * dc = DC_GetDCUpdate( hdc );
731 BOOL ret = FALSE;
733 if(!dc) return FALSE;
735 if(PATH_IsPathOpen(dc->w.path))
736 ret = PATH_PolylineTo(dc, pt, cCount);
738 else if(dc->funcs->pPolylineTo)
739 ret = dc->funcs->pPolylineTo(dc, pt, cCount);
741 else { /* do it using Polyline */
742 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
743 sizeof(POINT) * (cCount + 1) );
744 if (pts)
746 pts[0].x = dc->w.CursPosX;
747 pts[0].y = dc->w.CursPosY;
748 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
749 ret = Polyline( hdc, pts, cCount + 1 );
750 HeapFree( GetProcessHeap(), 0, pts );
753 if(ret) {
754 dc->w.CursPosX = pt[cCount-1].x;
755 dc->w.CursPosY = pt[cCount-1].y;
757 GDI_ReleaseObj( hdc );
758 return ret;
761 /**********************************************************************
762 * Polygon16 (GDI.36)
764 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
766 register int i;
767 BOOL ret;
768 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
769 count*sizeof(POINT) );
771 if (!pt32) return FALSE;
772 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
773 ret = Polygon(hdc,pt32,count);
774 HeapFree( GetProcessHeap(), 0, pt32 );
775 return ret;
779 /**********************************************************************
780 * Polygon (GDI32.275)
782 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
784 BOOL ret = FALSE;
785 DC * dc = DC_GetDCUpdate( hdc );
786 if (dc)
788 if (PATH_IsPathOpen(dc->w.path)) ret = PATH_Polygon(dc, pt, count);
789 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc,pt,count);
790 GDI_ReleaseObj( hdc );
792 return ret;
796 /**********************************************************************
797 * PolyPolygon16 (GDI.450)
799 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
800 UINT16 polygons )
802 int i,nrpts;
803 LPPOINT pt32;
804 LPINT counts32;
805 BOOL16 ret;
807 nrpts=0;
808 for (i=polygons;i--;)
809 nrpts+=counts[i];
810 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
811 if(pt32 == NULL) return FALSE;
812 for (i=nrpts;i--;)
813 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
814 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
815 if(counts32 == NULL) {
816 HeapFree( GetProcessHeap(), 0, pt32 );
817 return FALSE;
819 for (i=polygons;i--;) counts32[i]=counts[i];
821 ret = PolyPolygon(hdc,pt32,counts32,polygons);
822 HeapFree( GetProcessHeap(), 0, counts32 );
823 HeapFree( GetProcessHeap(), 0, pt32 );
824 return ret;
827 /**********************************************************************
828 * PolyPolygon (GDI.450)
830 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
831 UINT polygons )
833 BOOL ret = FALSE;
834 DC * dc = DC_GetDCUpdate( hdc );
835 if (dc)
837 if (PATH_IsPathOpen(dc->w.path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
838 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
839 GDI_ReleaseObj( hdc );
841 return ret;
844 /**********************************************************************
845 * PolyPolyline (GDI32.272)
847 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
848 DWORD polylines )
850 BOOL ret = FALSE;
851 DC * dc = DC_GetDCUpdate( hdc );
852 if (dc)
854 if (PATH_IsPathOpen(dc->w.path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
855 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
856 GDI_ReleaseObj( hdc );
858 return ret;
861 /**********************************************************************
862 * ExtFloodFill16 (GDI.372)
864 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
865 UINT16 fillType )
867 return ExtFloodFill( hdc, x, y, color, fillType );
871 /**********************************************************************
872 * ExtFloodFill (GDI32.96)
874 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
875 UINT fillType )
877 BOOL ret = FALSE;
878 DC * dc = DC_GetDCUpdate( hdc );
879 if (dc)
881 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
882 GDI_ReleaseObj( hdc );
884 return ret;
888 /**********************************************************************
889 * FloodFill16 (GDI.25)
891 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
893 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
897 /**********************************************************************
898 * FloodFill (GDI32.104)
900 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
902 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
906 /******************************************************************************
907 * PolyBezier16 [GDI.502]
909 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
911 int i;
912 BOOL16 ret;
913 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
914 cPoints*sizeof(POINT) );
915 if(!pt32) return FALSE;
916 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
917 ret= PolyBezier(hDc, pt32, cPoints);
918 HeapFree( GetProcessHeap(), 0, pt32 );
919 return ret;
922 /******************************************************************************
923 * PolyBezierTo16 [GDI.503]
925 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
927 int i;
928 BOOL16 ret;
929 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
930 cPoints*sizeof(POINT) );
931 if(!pt32) return FALSE;
932 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
933 ret= PolyBezierTo(hDc, pt32, cPoints);
934 HeapFree( GetProcessHeap(), 0, pt32 );
935 return ret;
938 /******************************************************************************
939 * PolyBezier [GDI32.268]
940 * Draws one or more Bezier curves
942 * PARAMS
943 * hDc [I] Handle to device context
944 * lppt [I] Pointer to endpoints and control points
945 * cPoints [I] Count of endpoints and control points
947 * RETURNS STD
949 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
951 BOOL ret = FALSE;
952 DC * dc = DC_GetDCUpdate( hdc );
954 if(!dc) return FALSE;
956 if(PATH_IsPathOpen(dc->w.path))
957 ret = PATH_PolyBezier(dc, lppt, cPoints);
958 else if (dc->funcs->pPolyBezier)
959 ret = dc->funcs->pPolyBezier(dc, lppt, cPoints);
960 else /* We'll convert it into line segments and draw them using Polyline */
962 POINT *Pts;
963 INT nOut;
965 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
967 TRACE("Pts = %p, no = %d\n", Pts, nOut);
968 ret = Polyline( dc->hSelf, Pts, nOut );
969 HeapFree( GetProcessHeap(), 0, Pts );
973 GDI_ReleaseObj( hdc );
974 return ret;
977 /******************************************************************************
978 * PolyBezierTo [GDI32.269]
979 * Draws one or more Bezier curves
981 * PARAMS
982 * hDc [I] Handle to device context
983 * lppt [I] Pointer to endpoints and control points
984 * cPoints [I] Count of endpoints and control points
986 * RETURNS STD
988 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
990 DC * dc = DC_GetDCUpdate( hdc );
991 BOOL ret;
993 if(!dc) return FALSE;
995 if(PATH_IsPathOpen(dc->w.path))
996 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
997 else if(dc->funcs->pPolyBezierTo)
998 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
999 else { /* We'll do it using PolyBezier */
1000 POINT *pt;
1001 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
1002 if(!pt) return FALSE;
1003 pt[0].x = dc->w.CursPosX;
1004 pt[0].y = dc->w.CursPosY;
1005 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
1006 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
1007 HeapFree( GetProcessHeap(), 0, pt );
1009 if(ret) {
1010 dc->w.CursPosX = lppt[cPoints-1].x;
1011 dc->w.CursPosY = lppt[cPoints-1].y;
1013 GDI_ReleaseObj( hdc );
1014 return ret;
1017 /***********************************************************************
1018 * AngleArc (GDI32.5)
1021 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
1022 FLOAT eStartAngle, FLOAT eSweepAngle)
1024 int x1,y1,x2,y2;
1025 BOOL result;
1026 DC *dc;
1028 if( (signed int)dwRadius < 0 )
1029 return FALSE;
1031 dc = DC_GetDCUpdate( hdc );
1032 if(!dc) return FALSE;
1034 if(dc->funcs->pAngleArc)
1036 result = dc->funcs->pAngleArc( dc, x, y, dwRadius, eStartAngle, eSweepAngle );
1037 GDI_ReleaseObj( hdc );
1038 return result;
1040 GDI_ReleaseObj( hdc );
1042 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1043 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1044 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1045 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1047 LineTo( hdc, x1, y1 );
1048 if( eSweepAngle >= 0 )
1049 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1050 x1, y1, x2, y2 );
1051 else
1052 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1053 x2, y2, x1, y1 );
1055 if( result ) MoveToEx( hdc, x2, y2, NULL );
1056 return result;
1059 /***********************************************************************
1060 * PolyDraw (GDI32.270)
1063 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1064 DWORD cCount)
1066 DC *dc;
1067 BOOL result;
1068 POINT lastmove;
1069 int i;
1071 dc = DC_GetDCUpdate( hdc );
1072 if(!dc) return FALSE;
1074 if(dc->funcs->pPolyDraw)
1076 result = dc->funcs->pPolyDraw( dc, lppt, lpbTypes, cCount );
1077 GDI_ReleaseObj( hdc );
1078 return result;
1080 GDI_ReleaseObj( hdc );
1082 /* check for each bezierto if there are two more points */
1083 for( i = 0; i < cCount; i++ )
1084 if( lpbTypes[i] != PT_MOVETO &&
1085 lpbTypes[i] & PT_BEZIERTO )
1087 if( cCount < i+3 )
1088 return FALSE;
1089 else
1090 i += 2;
1093 /* if no moveto occurs, we will close the figure here */
1094 lastmove.x = dc->w.CursPosX;
1095 lastmove.y = dc->w.CursPosY;
1097 /* now let's draw */
1098 for( i = 0; i < cCount; i++ )
1099 if( lpbTypes[i] == PT_MOVETO )
1101 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1102 lastmove.x = dc->w.CursPosX;
1103 lastmove.y = dc->w.CursPosY;
1105 else if( lpbTypes[i] & PT_LINETO )
1107 LineTo( hdc, lppt[i].x, lppt[i].y );
1108 if( lpbTypes[i] & PT_CLOSEFIGURE )
1109 LineTo( hdc, lastmove.x, lastmove.y );
1111 else if( lpbTypes[i] & PT_BEZIERTO )
1113 /* optimizeme: multiple BezierTo's with one PolyBezierTo call */
1114 PolyBezierTo( hdc, &lppt[i], 3 );
1116 i += 2;
1118 if( lpbTypes[i] & PT_CLOSEFIGURE )
1119 LineTo( hdc, lastmove.x, lastmove.y );
1121 else
1122 return FALSE;
1124 return TRUE;
1127 /******************************************************************
1129 * *Very* simple bezier drawing code,
1131 * It uses a recursive algorithm to divide the curve in a series
1132 * of straight line segements. Not ideal but for me sufficient.
1133 * If you are in need for something better look for some incremental
1134 * algorithm.
1136 * 7 July 1998 Rein Klazes
1140 * some macro definitions for bezier drawing
1142 * to avoid trucation errors the coordinates are
1143 * shifted upwards. When used in drawing they are
1144 * shifted down again, including correct rounding
1145 * and avoiding floating point arithmatic
1146 * 4 bits should allow 27 bits coordinates which I saw
1147 * somewere in the win32 doc's
1151 #define BEZIERSHIFTBITS 4
1152 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1153 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1154 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1155 /* maximum depth of recursion */
1156 #define BEZIERMAXDEPTH 8
1158 /* size of array to store points on */
1159 /* enough for one curve */
1160 #define BEZIER_INITBUFSIZE (150)
1162 /* calculate Bezier average, in this case the middle
1163 * correctly rounded...
1164 * */
1166 #define BEZIERMIDDLE(Mid, P1, P2) \
1167 (Mid).x=((P1).x+(P2).x + 1)/2;\
1168 (Mid).y=((P1).y+(P2).y + 1)/2;
1170 /**********************************************************
1171 * BezierCheck helper function to check
1172 * that recursion can be terminated
1173 * Points[0] and Points[3] are begin and endpoint
1174 * Points[1] and Points[2] are control points
1175 * level is the recursion depth
1176 * returns true if the recusion can be terminated
1178 static BOOL BezierCheck( int level, POINT *Points)
1180 INT dx, dy;
1181 dx=Points[3].x-Points[0].x;
1182 dy=Points[3].y-Points[0].y;
1183 if(abs(dy)<=abs(dx)){/* shallow line */
1184 /* check that control points are between begin and end */
1185 if(Points[1].x < Points[0].x){
1186 if(Points[1].x < Points[3].x)
1187 return FALSE;
1188 }else
1189 if(Points[1].x > Points[3].x)
1190 return FALSE;
1191 if(Points[2].x < Points[0].x){
1192 if(Points[2].x < Points[3].x)
1193 return FALSE;
1194 }else
1195 if(Points[2].x > Points[3].x)
1196 return FALSE;
1197 dx=BEZIERSHIFTDOWN(dx);
1198 if(!dx) return TRUE;
1199 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1200 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1201 abs(Points[2].y-Points[0].y-(dy/dx)*
1202 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1203 return FALSE;
1204 else
1205 return TRUE;
1206 }else{ /* steep line */
1207 /* check that control points are between begin and end */
1208 if(Points[1].y < Points[0].y){
1209 if(Points[1].y < Points[3].y)
1210 return FALSE;
1211 }else
1212 if(Points[1].y > Points[3].y)
1213 return FALSE;
1214 if(Points[2].y < Points[0].y){
1215 if(Points[2].y < Points[3].y)
1216 return FALSE;
1217 }else
1218 if(Points[2].y > Points[3].y)
1219 return FALSE;
1220 dy=BEZIERSHIFTDOWN(dy);
1221 if(!dy) return TRUE;
1222 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1223 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1224 abs(Points[2].x-Points[0].x-(dx/dy)*
1225 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1226 return FALSE;
1227 else
1228 return TRUE;
1232 /* Helper for GDI_Bezier.
1233 * Just handles one Bezier, so Points should point to four POINTs
1235 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1236 INT *nPtsOut, INT level )
1238 if(*nPtsOut == *dwOut) {
1239 *dwOut *= 2;
1240 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1241 *dwOut * sizeof(POINT) );
1244 if(!level || BezierCheck(level, Points)) {
1245 if(*nPtsOut == 0) {
1246 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1247 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1248 *nPtsOut = 1;
1250 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1251 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1252 (*nPtsOut) ++;
1253 } else {
1254 POINT Points2[4]; /* for the second recursive call */
1255 Points2[3]=Points[3];
1256 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1257 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1258 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1260 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1261 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1262 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1264 Points2[0]=Points[3];
1266 /* do the two halves */
1267 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1268 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1274 /***********************************************************************
1275 * GDI_Bezier [INTERNAL]
1276 * Calculate line segments that approximate -what microsoft calls- a bezier
1277 * curve.
1278 * The routine recursively divides the curve in two parts until a straight
1279 * line can be drawn
1281 * PARAMS
1283 * Points [I] Ptr to count POINTs which are the end and control points
1284 * of the set of Bezier curves to flatten.
1285 * count [I] Number of Points. Must be 3n+1.
1286 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1287 * lines+1).
1289 * RETURNS
1291 * Ptr to an array of POINTs that contain the lines that approximinate the
1292 * Beziers. The array is allocated on the process heap and it is the caller's
1293 * responsibility to HeapFree it. [this is not a particularly nice interface
1294 * but since we can't know in advance how many points will generate, the
1295 * alternative would be to call the function twice, once to determine the size
1296 * and a second time to do the work - I decided this was too much of a pain].
1298 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1300 POINT *out;
1301 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1303 if((count - 1) % 3 != 0) {
1304 ERR("Invalid no. of points\n");
1305 return NULL;
1307 *nPtsOut = 0;
1308 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1309 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1310 POINT ptBuf[4];
1311 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1312 for(i = 0; i < 4; i++) {
1313 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1314 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1316 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1318 TRACE("Produced %d points\n", *nPtsOut);
1319 return out;