- Minor API file update.
[wine.git] / graphics / painting.c
blobe43db113121fba075dfb0f73c04aa83ca46f84e3
1 /*
2 * GDI drawing functions.
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
6 * 1999 Huw D M Davies
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <string.h>
24 #include <stdlib.h>
26 #include "windef.h"
27 #include "wingdi.h"
28 #include "winerror.h"
29 #include "gdi.h"
30 #include "bitmap.h"
31 #include "region.h"
32 #include "path.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
38 /***********************************************************************
39 * LineTo (GDI.19)
41 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
43 return LineTo( hdc, x, y );
47 /***********************************************************************
48 * LineTo (GDI32.@)
50 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
52 DC * dc = DC_GetDCUpdate( hdc );
53 BOOL ret;
55 if(!dc) return FALSE;
57 if(PATH_IsPathOpen(dc->path))
58 ret = PATH_LineTo(dc, x, y);
59 else
60 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
61 if(ret) {
62 dc->CursPosX = x;
63 dc->CursPosY = y;
65 GDI_ReleaseObj( hdc );
66 return ret;
70 /***********************************************************************
71 * MoveTo (GDI.20)
73 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
75 POINT pt;
77 if (!MoveToEx( (HDC)hdc, x, y, &pt )) return 0;
78 return MAKELONG(pt.x,pt.y);
82 /***********************************************************************
83 * MoveToEx (GDI.483)
85 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
87 POINT pt32;
89 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
90 if (pt) CONV_POINT32TO16( &pt32, pt );
91 return TRUE;
95 /***********************************************************************
96 * MoveToEx (GDI32.@)
98 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
100 BOOL ret = TRUE;
101 DC * dc = DC_GetDCPtr( hdc );
103 if(!dc) return FALSE;
105 if(pt) {
106 pt->x = dc->CursPosX;
107 pt->y = dc->CursPosY;
109 dc->CursPosX = x;
110 dc->CursPosY = y;
112 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
113 else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
114 GDI_ReleaseObj( hdc );
115 return ret;
119 /***********************************************************************
120 * Arc (GDI.23)
122 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
123 INT16 bottom, INT16 xstart, INT16 ystart,
124 INT16 xend, INT16 yend )
126 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
127 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
128 (INT)yend );
132 /***********************************************************************
133 * Arc (GDI32.@)
135 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
136 INT bottom, INT xstart, INT ystart,
137 INT xend, INT yend )
139 BOOL ret = FALSE;
140 DC * dc = DC_GetDCUpdate( hdc );
141 if (dc)
143 if(PATH_IsPathOpen(dc->path))
144 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
145 else if (dc->funcs->pArc)
146 ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
147 GDI_ReleaseObj( hdc );
149 return ret;
152 /***********************************************************************
153 * ArcTo (GDI32.@)
155 BOOL WINAPI ArcTo( HDC hdc,
156 INT left, INT top,
157 INT right, INT bottom,
158 INT xstart, INT ystart,
159 INT xend, INT yend )
161 BOOL result;
162 DC * dc = DC_GetDCUpdate( hdc );
163 if(!dc) return FALSE;
165 if(dc->funcs->pArcTo)
167 result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
168 xstart, ystart, xend, yend );
169 GDI_ReleaseObj( hdc );
170 return result;
172 GDI_ReleaseObj( hdc );
174 * Else emulate it.
175 * According to the documentation, a line is drawn from the current
176 * position to the starting point of the arc.
178 LineTo(hdc, xstart, ystart);
180 * Then the arc is drawn.
182 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
184 * If no error occurred, the current position is moved to the ending
185 * point of the arc.
187 if (result) MoveToEx(hdc, xend, yend, NULL);
188 return result;
191 /***********************************************************************
192 * Pie (GDI.26)
194 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
195 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
196 INT16 xend, INT16 yend )
198 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
199 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
200 (INT)yend );
204 /***********************************************************************
205 * Pie (GDI32.@)
207 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
208 INT right, INT bottom, INT xstart, INT ystart,
209 INT xend, INT yend )
211 BOOL ret = FALSE;
212 DC * dc = DC_GetDCUpdate( hdc );
213 if (!dc) return FALSE;
215 if(PATH_IsPathOpen(dc->path))
216 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
217 else if(dc->funcs->pPie)
218 ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
220 GDI_ReleaseObj( hdc );
221 return ret;
225 /***********************************************************************
226 * Chord (GDI.348)
228 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
229 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
230 INT16 xend, INT16 yend )
232 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
236 /***********************************************************************
237 * Chord (GDI32.@)
239 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
240 INT right, INT bottom, INT xstart, INT ystart,
241 INT xend, INT yend )
243 BOOL ret = FALSE;
244 DC * dc = DC_GetDCUpdate( hdc );
245 if (!dc) return FALSE;
247 if(PATH_IsPathOpen(dc->path))
248 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
249 else if(dc->funcs->pChord)
250 ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
252 GDI_ReleaseObj( hdc );
253 return ret;
257 /***********************************************************************
258 * Ellipse (GDI.24)
260 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
261 INT16 right, INT16 bottom )
263 return Ellipse( hdc, left, top, right, bottom );
267 /***********************************************************************
268 * Ellipse (GDI32.@)
270 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
271 INT right, INT bottom )
273 BOOL ret = FALSE;
274 DC * dc = DC_GetDCUpdate( hdc );
275 if (!dc) return FALSE;
277 if(PATH_IsPathOpen(dc->path))
278 ret = PATH_Ellipse(dc,left,top,right,bottom);
279 else if (dc->funcs->pEllipse)
280 ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
282 GDI_ReleaseObj( hdc );
283 return ret;
287 /***********************************************************************
288 * Rectangle (GDI.27)
290 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
291 INT16 right, INT16 bottom )
293 return Rectangle( hdc, left, top, right, bottom );
297 /***********************************************************************
298 * Rectangle (GDI32.@)
300 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
301 INT right, INT bottom )
303 BOOL ret = FALSE;
304 DC * dc = DC_GetDCUpdate( hdc );
305 if (dc)
307 if(PATH_IsPathOpen(dc->path))
308 ret = PATH_Rectangle(dc, left, top, right, bottom);
309 else if (dc->funcs->pRectangle)
310 ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
311 GDI_ReleaseObj( hdc );
313 return ret;
317 /***********************************************************************
318 * RoundRect (GDI.28)
320 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
321 INT16 bottom, INT16 ell_width, INT16 ell_height )
323 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
327 /***********************************************************************
328 * RoundRect (GDI32.@)
330 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
331 INT bottom, INT ell_width, INT ell_height )
333 BOOL ret = FALSE;
334 DC *dc = DC_GetDCUpdate( hdc );
336 if (dc)
338 if(PATH_IsPathOpen(dc->path))
339 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
340 else if (dc->funcs->pRoundRect)
341 ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
342 GDI_ReleaseObj( hdc );
344 return ret;
347 /***********************************************************************
348 * SetPixel (GDI.31)
350 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
352 return SetPixel( hdc, x, y, color );
356 /***********************************************************************
357 * SetPixel (GDI32.@)
359 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
361 COLORREF ret = 0;
362 DC * dc = DC_GetDCUpdate( hdc );
363 if (dc)
365 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
366 GDI_ReleaseObj( hdc );
368 return ret;
371 /***********************************************************************
372 * SetPixelV (GDI32.@)
374 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
376 BOOL ret = FALSE;
377 DC * dc = DC_GetDCUpdate( hdc );
378 if (dc)
380 if (dc->funcs->pSetPixel)
382 dc->funcs->pSetPixel(dc->physDev,x,y,color);
383 ret = TRUE;
385 GDI_ReleaseObj( hdc );
387 return ret;
390 /***********************************************************************
391 * GetPixel (GDI.83)
393 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
395 return GetPixel( hdc, x, y );
399 /***********************************************************************
400 * GetPixel (GDI32.@)
402 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
404 COLORREF ret = CLR_INVALID;
405 DC * dc = DC_GetDCUpdate( hdc );
407 if (dc)
409 /* FIXME: should this be in the graphics driver? */
410 if (PtVisible( hdc, x, y ))
412 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
414 GDI_ReleaseObj( hdc );
416 return ret;
420 /******************************************************************************
421 * ChoosePixelFormat [GDI32.@]
422 * Matches a pixel format to given format
424 * PARAMS
425 * hdc [I] Device context to search for best pixel match
426 * ppfd [I] Pixel format for which a match is sought
428 * RETURNS
429 * Success: Pixel format index closest to given format
430 * Failure: 0
432 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
434 INT ret = 0;
435 DC * dc = DC_GetDCPtr( hdc );
437 TRACE("(%08x,%p)\n",hdc,ppfd);
439 if (!dc) return 0;
441 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
442 else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
444 GDI_ReleaseObj( hdc );
445 return ret;
449 /******************************************************************************
450 * SetPixelFormat [GDI32.@]
451 * Sets pixel format of device context
453 * PARAMS
454 * hdc [I] Device context to search for best pixel match
455 * iPixelFormat [I] Pixel format index
456 * ppfd [I] Pixel format for which a match is sought
458 * RETURNS STD
460 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
461 const PIXELFORMATDESCRIPTOR *ppfd)
463 INT bRet = FALSE;
464 DC * dc = DC_GetDCPtr( hdc );
466 TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
468 if (!dc) return 0;
470 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
471 else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
473 GDI_ReleaseObj( hdc );
474 return bRet;
478 /******************************************************************************
479 * GetPixelFormat [GDI32.@]
480 * Gets index of pixel format of DC
482 * PARAMETERS
483 * hdc [I] Device context whose pixel format index is sought
485 * RETURNS
486 * Success: Currently selected pixel format
487 * Failure: 0
489 INT WINAPI GetPixelFormat( HDC hdc )
491 INT ret = 0;
492 DC * dc = DC_GetDCPtr( hdc );
494 TRACE("(%08x)\n",hdc);
496 if (!dc) return 0;
498 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
499 else ret = dc->funcs->pGetPixelFormat(dc->physDev);
501 GDI_ReleaseObj( hdc );
502 return ret;
506 /******************************************************************************
507 * DescribePixelFormat [GDI32.@]
508 * Gets info about pixel format from DC
510 * PARAMS
511 * hdc [I] Device context
512 * iPixelFormat [I] Pixel format selector
513 * nBytes [I] Size of buffer
514 * ppfd [O] Pointer to structure to receive pixel format data
516 * RETURNS
517 * Success: Maximum pixel format index of the device context
518 * Failure: 0
520 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
521 LPPIXELFORMATDESCRIPTOR ppfd )
523 INT ret = 0;
524 DC * dc = DC_GetDCPtr( hdc );
526 TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
528 if (!dc) return 0;
530 if (!dc->funcs->pDescribePixelFormat)
532 FIXME(" :stub\n");
533 ppfd->nSize = nBytes;
534 ppfd->nVersion = 1;
535 ret = 3;
537 else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
539 GDI_ReleaseObj( hdc );
540 return ret;
544 /******************************************************************************
545 * SwapBuffers [GDI32.@]
546 * Exchanges front and back buffers of window
548 * PARAMS
549 * hdc [I] Device context whose buffers get swapped
551 * RETURNS STD
553 BOOL WINAPI SwapBuffers( HDC hdc )
555 INT bRet = FALSE;
556 DC * dc = DC_GetDCPtr( hdc );
558 TRACE("(%08x)\n",hdc);
560 if (!dc) return TRUE;
562 if (!dc->funcs->pSwapBuffers)
564 FIXME(" :stub\n");
565 bRet = TRUE;
567 else bRet = dc->funcs->pSwapBuffers(dc->physDev);
569 GDI_ReleaseObj( hdc );
570 return bRet;
574 /***********************************************************************
575 * PaintRgn (GDI.43)
577 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
579 return PaintRgn( hdc, hrgn );
583 /***********************************************************************
584 * PaintRgn (GDI32.@)
586 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
588 BOOL ret = FALSE;
589 DC * dc = DC_GetDCUpdate( hdc );
590 if (dc)
592 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
593 GDI_ReleaseObj( hdc );
595 return ret;
599 /***********************************************************************
600 * FillRgn (GDI.40)
602 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
604 return FillRgn( hdc, hrgn, hbrush );
608 /***********************************************************************
609 * FillRgn (GDI32.@)
611 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
613 BOOL retval = FALSE;
614 HBRUSH prevBrush;
615 DC * dc = DC_GetDCUpdate( hdc );
617 if (!dc) return FALSE;
618 if(dc->funcs->pFillRgn)
619 retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
620 else if ((prevBrush = SelectObject( hdc, hbrush )))
622 retval = PaintRgn( hdc, hrgn );
623 SelectObject( hdc, prevBrush );
625 GDI_ReleaseObj( hdc );
626 return retval;
630 /***********************************************************************
631 * FrameRgn (GDI.41)
633 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
634 INT16 nWidth, INT16 nHeight )
636 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
640 /***********************************************************************
641 * FrameRgn (GDI32.@)
643 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
644 INT nWidth, INT nHeight )
646 BOOL ret = FALSE;
647 DC *dc = DC_GetDCUpdate( hdc );
649 if (!dc) return FALSE;
650 if(dc->funcs->pFrameRgn)
651 ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
652 else
654 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
655 if (tmp)
657 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
659 FillRgn( hdc, tmp, hbrush );
660 ret = TRUE;
662 DeleteObject( tmp );
665 GDI_ReleaseObj( hdc );
666 return ret;
670 /***********************************************************************
671 * InvertRgn (GDI.42)
673 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
675 return InvertRgn( hdc, hrgn );
679 /***********************************************************************
680 * InvertRgn (GDI32.@)
682 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
684 HBRUSH prevBrush;
685 INT prevROP;
686 BOOL retval;
687 DC *dc = DC_GetDCUpdate( hdc );
688 if (!dc) return FALSE;
690 if(dc->funcs->pInvertRgn)
691 retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
692 else
694 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
695 prevROP = SetROP2( hdc, R2_NOT );
696 retval = PaintRgn( hdc, hrgn );
697 SelectObject( hdc, prevBrush );
698 SetROP2( hdc, prevROP );
700 GDI_ReleaseObj( hdc );
701 return retval;
704 /**********************************************************************
705 * Polyline (GDI.37)
707 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
709 register int i;
710 BOOL16 ret;
711 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
712 count*sizeof(POINT) );
714 if (!pt32) return FALSE;
715 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
716 ret = Polyline(hdc,pt32,count);
717 HeapFree( GetProcessHeap(), 0, pt32 );
718 return ret;
722 /**********************************************************************
723 * Polyline (GDI32.@)
725 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
727 BOOL ret = FALSE;
728 DC * dc = DC_GetDCUpdate( hdc );
729 if (dc)
731 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
732 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
733 GDI_ReleaseObj( hdc );
735 return ret;
738 /**********************************************************************
739 * PolylineTo (GDI32.@)
741 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
743 DC * dc = DC_GetDCUpdate( hdc );
744 BOOL ret = FALSE;
746 if(!dc) return FALSE;
748 if(PATH_IsPathOpen(dc->path))
749 ret = PATH_PolylineTo(dc, pt, cCount);
751 else if(dc->funcs->pPolylineTo)
752 ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
754 else { /* do it using Polyline */
755 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
756 sizeof(POINT) * (cCount + 1) );
757 if (pts)
759 pts[0].x = dc->CursPosX;
760 pts[0].y = dc->CursPosY;
761 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
762 ret = Polyline( hdc, pts, cCount + 1 );
763 HeapFree( GetProcessHeap(), 0, pts );
766 if(ret) {
767 dc->CursPosX = pt[cCount-1].x;
768 dc->CursPosY = pt[cCount-1].y;
770 GDI_ReleaseObj( hdc );
771 return ret;
774 /**********************************************************************
775 * Polygon (GDI.36)
777 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
779 register int i;
780 BOOL ret;
781 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
782 count*sizeof(POINT) );
784 if (!pt32) return FALSE;
785 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
786 ret = Polygon(hdc,pt32,count);
787 HeapFree( GetProcessHeap(), 0, pt32 );
788 return ret;
792 /**********************************************************************
793 * Polygon (GDI32.@)
795 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
797 BOOL ret = FALSE;
798 DC * dc = DC_GetDCUpdate( hdc );
799 if (dc)
801 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
802 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
803 GDI_ReleaseObj( hdc );
805 return ret;
809 /**********************************************************************
810 * PolyPolygon (GDI.450)
812 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
813 UINT16 polygons )
815 int i,nrpts;
816 LPPOINT pt32;
817 LPINT counts32;
818 BOOL16 ret;
820 nrpts=0;
821 for (i=polygons;i--;)
822 nrpts+=counts[i];
823 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
824 if(pt32 == NULL) return FALSE;
825 for (i=nrpts;i--;)
826 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
827 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
828 if(counts32 == NULL) {
829 HeapFree( GetProcessHeap(), 0, pt32 );
830 return FALSE;
832 for (i=polygons;i--;) counts32[i]=counts[i];
834 ret = PolyPolygon(hdc,pt32,counts32,polygons);
835 HeapFree( GetProcessHeap(), 0, counts32 );
836 HeapFree( GetProcessHeap(), 0, pt32 );
837 return ret;
840 /**********************************************************************
841 * PolyPolygon (GDI32.@)
843 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
844 UINT polygons )
846 BOOL ret = FALSE;
847 DC * dc = DC_GetDCUpdate( hdc );
848 if (dc)
850 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
851 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
852 GDI_ReleaseObj( hdc );
854 return ret;
857 /**********************************************************************
858 * PolyPolyline (GDI32.@)
860 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
861 DWORD polylines )
863 BOOL ret = FALSE;
864 DC * dc = DC_GetDCUpdate( hdc );
865 if (dc)
867 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
868 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
869 GDI_ReleaseObj( hdc );
871 return ret;
874 /**********************************************************************
875 * ExtFloodFill (GDI.372)
877 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
878 UINT16 fillType )
880 return ExtFloodFill( hdc, x, y, color, fillType );
884 /**********************************************************************
885 * ExtFloodFill (GDI32.@)
887 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
888 UINT fillType )
890 BOOL ret = FALSE;
891 DC * dc = DC_GetDCUpdate( hdc );
892 if (dc)
894 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
895 GDI_ReleaseObj( hdc );
897 return ret;
901 /**********************************************************************
902 * FloodFill (GDI.25)
904 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
906 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
910 /**********************************************************************
911 * FloodFill (GDI32.@)
913 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
915 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
919 /******************************************************************************
920 * PolyBezier [GDI.502]
922 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
924 int i;
925 BOOL16 ret;
926 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
927 cPoints*sizeof(POINT) );
928 if(!pt32) return FALSE;
929 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
930 ret= PolyBezier(hDc, pt32, cPoints);
931 HeapFree( GetProcessHeap(), 0, pt32 );
932 return ret;
935 /******************************************************************************
936 * PolyBezierTo [GDI.503]
938 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
940 int i;
941 BOOL16 ret;
942 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
943 cPoints*sizeof(POINT) );
944 if(!pt32) return FALSE;
945 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
946 ret= PolyBezierTo(hDc, pt32, cPoints);
947 HeapFree( GetProcessHeap(), 0, pt32 );
948 return ret;
951 /******************************************************************************
952 * PolyBezier [GDI32.@]
953 * Draws one or more Bezier curves
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
960 * RETURNS STD
962 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
964 BOOL ret = FALSE;
965 DC * dc = DC_GetDCUpdate( hdc );
967 if(!dc) return FALSE;
969 if(PATH_IsPathOpen(dc->path))
970 ret = PATH_PolyBezier(dc, lppt, cPoints);
971 else if (dc->funcs->pPolyBezier)
972 ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
973 else /* We'll convert it into line segments and draw them using Polyline */
975 POINT *Pts;
976 INT nOut;
978 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
980 TRACE("Pts = %p, no = %d\n", Pts, nOut);
981 ret = Polyline( dc->hSelf, Pts, nOut );
982 HeapFree( GetProcessHeap(), 0, Pts );
986 GDI_ReleaseObj( hdc );
987 return ret;
990 /******************************************************************************
991 * PolyBezierTo [GDI32.@]
992 * Draws one or more Bezier curves
994 * PARAMS
995 * hDc [I] Handle to device context
996 * lppt [I] Pointer to endpoints and control points
997 * cPoints [I] Count of endpoints and control points
999 * RETURNS STD
1001 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
1003 DC * dc = DC_GetDCUpdate( hdc );
1004 BOOL ret;
1006 if(!dc) return FALSE;
1008 if(PATH_IsPathOpen(dc->path))
1009 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
1010 else if(dc->funcs->pPolyBezierTo)
1011 ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
1012 else { /* We'll do it using PolyBezier */
1013 POINT *pt;
1014 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
1015 if(!pt) return FALSE;
1016 pt[0].x = dc->CursPosX;
1017 pt[0].y = dc->CursPosY;
1018 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
1019 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
1020 HeapFree( GetProcessHeap(), 0, pt );
1022 if(ret) {
1023 dc->CursPosX = lppt[cPoints-1].x;
1024 dc->CursPosY = lppt[cPoints-1].y;
1026 GDI_ReleaseObj( hdc );
1027 return ret;
1030 /***********************************************************************
1031 * AngleArc (GDI32.@)
1033 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1035 INT x1,y1,x2,y2, arcdir;
1036 BOOL result;
1037 DC *dc;
1039 if( (signed int)dwRadius < 0 )
1040 return FALSE;
1042 dc = DC_GetDCUpdate( hdc );
1043 if(!dc) return FALSE;
1045 if(dc->funcs->pAngleArc)
1047 result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
1049 GDI_ReleaseObj( hdc );
1050 return result;
1052 GDI_ReleaseObj( hdc );
1054 /* AngleArc always works counterclockwise */
1055 arcdir = GetArcDirection( hdc );
1056 SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
1058 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1059 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1060 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1061 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1063 LineTo( hdc, x1, y1 );
1064 if( eSweepAngle >= 0 )
1065 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1066 x1, y1, x2, y2 );
1067 else
1068 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1069 x2, y2, x1, y1 );
1071 if( result ) MoveToEx( hdc, x2, y2, NULL );
1072 SetArcDirection( hdc, arcdir );
1073 return result;
1076 /***********************************************************************
1077 * PolyDraw (GDI32.@)
1079 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1080 DWORD cCount)
1082 DC *dc;
1083 BOOL result;
1084 POINT lastmove;
1085 int i;
1087 dc = DC_GetDCUpdate( hdc );
1088 if(!dc) return FALSE;
1090 if(dc->funcs->pPolyDraw)
1092 result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
1093 GDI_ReleaseObj( hdc );
1094 return result;
1096 GDI_ReleaseObj( hdc );
1098 /* check for each bezierto if there are two more points */
1099 for( i = 0; i < cCount; i++ )
1100 if( lpbTypes[i] != PT_MOVETO &&
1101 lpbTypes[i] & PT_BEZIERTO )
1103 if( cCount < i+3 )
1104 return FALSE;
1105 else
1106 i += 2;
1109 /* if no moveto occurs, we will close the figure here */
1110 lastmove.x = dc->CursPosX;
1111 lastmove.y = dc->CursPosY;
1113 /* now let's draw */
1114 for( i = 0; i < cCount; i++ )
1116 if( lpbTypes[i] == PT_MOVETO )
1118 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1119 lastmove.x = dc->CursPosX;
1120 lastmove.y = dc->CursPosY;
1122 else if( lpbTypes[i] & PT_LINETO )
1123 LineTo( hdc, lppt[i].x, lppt[i].y );
1124 else if( lpbTypes[i] & PT_BEZIERTO )
1126 PolyBezierTo( hdc, &lppt[i], 3 );
1127 i += 2;
1129 else
1130 return FALSE;
1132 if( lpbTypes[i] & PT_CLOSEFIGURE )
1134 if( PATH_IsPathOpen( dc->path ) )
1135 CloseFigure( hdc );
1136 else
1137 LineTo( hdc, lastmove.x, lastmove.y );
1141 return TRUE;
1144 /******************************************************************
1146 * *Very* simple bezier drawing code,
1148 * It uses a recursive algorithm to divide the curve in a series
1149 * of straight line segements. Not ideal but for me sufficient.
1150 * If you are in need for something better look for some incremental
1151 * algorithm.
1153 * 7 July 1998 Rein Klazes
1157 * some macro definitions for bezier drawing
1159 * to avoid trucation errors the coordinates are
1160 * shifted upwards. When used in drawing they are
1161 * shifted down again, including correct rounding
1162 * and avoiding floating point arithmatic
1163 * 4 bits should allow 27 bits coordinates which I saw
1164 * somewere in the win32 doc's
1168 #define BEZIERSHIFTBITS 4
1169 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1170 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1171 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1172 /* maximum depth of recursion */
1173 #define BEZIERMAXDEPTH 8
1175 /* size of array to store points on */
1176 /* enough for one curve */
1177 #define BEZIER_INITBUFSIZE (150)
1179 /* calculate Bezier average, in this case the middle
1180 * correctly rounded...
1181 * */
1183 #define BEZIERMIDDLE(Mid, P1, P2) \
1184 (Mid).x=((P1).x+(P2).x + 1)/2;\
1185 (Mid).y=((P1).y+(P2).y + 1)/2;
1187 /**********************************************************
1188 * BezierCheck helper function to check
1189 * that recursion can be terminated
1190 * Points[0] and Points[3] are begin and endpoint
1191 * Points[1] and Points[2] are control points
1192 * level is the recursion depth
1193 * returns true if the recusion can be terminated
1195 static BOOL BezierCheck( int level, POINT *Points)
1197 INT dx, dy;
1198 dx=Points[3].x-Points[0].x;
1199 dy=Points[3].y-Points[0].y;
1200 if(abs(dy)<=abs(dx)){/* shallow line */
1201 /* check that control points are between begin and end */
1202 if(Points[1].x < Points[0].x){
1203 if(Points[1].x < Points[3].x)
1204 return FALSE;
1205 }else
1206 if(Points[1].x > Points[3].x)
1207 return FALSE;
1208 if(Points[2].x < Points[0].x){
1209 if(Points[2].x < Points[3].x)
1210 return FALSE;
1211 }else
1212 if(Points[2].x > Points[3].x)
1213 return FALSE;
1214 dx=BEZIERSHIFTDOWN(dx);
1215 if(!dx) return TRUE;
1216 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1217 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1218 abs(Points[2].y-Points[0].y-(dy/dx)*
1219 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1220 return FALSE;
1221 else
1222 return TRUE;
1223 }else{ /* steep line */
1224 /* check that control points are between begin and end */
1225 if(Points[1].y < Points[0].y){
1226 if(Points[1].y < Points[3].y)
1227 return FALSE;
1228 }else
1229 if(Points[1].y > Points[3].y)
1230 return FALSE;
1231 if(Points[2].y < Points[0].y){
1232 if(Points[2].y < Points[3].y)
1233 return FALSE;
1234 }else
1235 if(Points[2].y > Points[3].y)
1236 return FALSE;
1237 dy=BEZIERSHIFTDOWN(dy);
1238 if(!dy) return TRUE;
1239 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1240 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1241 abs(Points[2].x-Points[0].x-(dx/dy)*
1242 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1243 return FALSE;
1244 else
1245 return TRUE;
1249 /* Helper for GDI_Bezier.
1250 * Just handles one Bezier, so Points should point to four POINTs
1252 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1253 INT *nPtsOut, INT level )
1255 if(*nPtsOut == *dwOut) {
1256 *dwOut *= 2;
1257 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1258 *dwOut * sizeof(POINT) );
1261 if(!level || BezierCheck(level, Points)) {
1262 if(*nPtsOut == 0) {
1263 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1264 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1265 *nPtsOut = 1;
1267 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1268 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1269 (*nPtsOut) ++;
1270 } else {
1271 POINT Points2[4]; /* for the second recursive call */
1272 Points2[3]=Points[3];
1273 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1274 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1275 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1277 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1278 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1279 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1281 Points2[0]=Points[3];
1283 /* do the two halves */
1284 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1285 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1291 /***********************************************************************
1292 * GDI_Bezier [INTERNAL]
1293 * Calculate line segments that approximate -what microsoft calls- a bezier
1294 * curve.
1295 * The routine recursively divides the curve in two parts until a straight
1296 * line can be drawn
1298 * PARAMS
1300 * Points [I] Ptr to count POINTs which are the end and control points
1301 * of the set of Bezier curves to flatten.
1302 * count [I] Number of Points. Must be 3n+1.
1303 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1304 * lines+1).
1306 * RETURNS
1308 * Ptr to an array of POINTs that contain the lines that approximinate the
1309 * Beziers. The array is allocated on the process heap and it is the caller's
1310 * responsibility to HeapFree it. [this is not a particularly nice interface
1311 * but since we can't know in advance how many points will generate, the
1312 * alternative would be to call the function twice, once to determine the size
1313 * and a second time to do the work - I decided this was too much of a pain].
1315 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1317 POINT *out;
1318 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1320 if((count - 1) % 3 != 0) {
1321 ERR("Invalid no. of points\n");
1322 return NULL;
1324 *nPtsOut = 0;
1325 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1326 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1327 POINT ptBuf[4];
1328 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1329 for(i = 0; i < 4; i++) {
1330 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1331 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1333 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1335 TRACE("Produced %d points\n", *nPtsOut);
1336 return out;