Fix use of LOCALE_NOUSEROVERRIDE flag in GetNumberFormatA and
[wine.git] / graphics / painting.c
blob20ac608bfcb3c21b43494dd7a52e2c3d4553db17
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 "path.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
37 /***********************************************************************
38 * LineTo (GDI.19)
40 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
42 return LineTo( hdc, x, y );
46 /***********************************************************************
47 * LineTo (GDI32.@)
49 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
51 DC * dc = DC_GetDCUpdate( hdc );
52 BOOL ret;
54 if(!dc) return FALSE;
56 if(PATH_IsPathOpen(dc->path))
57 ret = PATH_LineTo(dc, x, y);
58 else
59 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
60 if(ret) {
61 dc->CursPosX = x;
62 dc->CursPosY = y;
64 GDI_ReleaseObj( hdc );
65 return ret;
69 /***********************************************************************
70 * MoveTo (GDI.20)
72 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
74 POINT pt;
76 if (!MoveToEx( (HDC)hdc, x, y, &pt )) return 0;
77 return MAKELONG(pt.x,pt.y);
81 /***********************************************************************
82 * MoveToEx (GDI.483)
84 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
86 POINT pt32;
88 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
89 if (pt) CONV_POINT32TO16( &pt32, pt );
90 return TRUE;
94 /***********************************************************************
95 * MoveToEx (GDI32.@)
97 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
99 BOOL ret = TRUE;
100 DC * dc = DC_GetDCPtr( hdc );
102 if(!dc) return FALSE;
104 if(pt) {
105 pt->x = dc->CursPosX;
106 pt->y = dc->CursPosY;
108 dc->CursPosX = x;
109 dc->CursPosY = y;
111 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
112 else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
113 GDI_ReleaseObj( hdc );
114 return ret;
118 /***********************************************************************
119 * Arc (GDI.23)
121 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
122 INT16 bottom, INT16 xstart, INT16 ystart,
123 INT16 xend, INT16 yend )
125 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
126 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
127 (INT)yend );
131 /***********************************************************************
132 * Arc (GDI32.@)
134 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
135 INT bottom, INT xstart, INT ystart,
136 INT xend, INT yend )
138 BOOL ret = FALSE;
139 DC * dc = DC_GetDCUpdate( hdc );
140 if (dc)
142 if(PATH_IsPathOpen(dc->path))
143 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
144 else if (dc->funcs->pArc)
145 ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
146 GDI_ReleaseObj( hdc );
148 return ret;
151 /***********************************************************************
152 * ArcTo (GDI32.@)
154 BOOL WINAPI ArcTo( HDC hdc,
155 INT left, INT top,
156 INT right, INT bottom,
157 INT xstart, INT ystart,
158 INT xend, INT yend )
160 BOOL result;
161 DC * dc = DC_GetDCUpdate( hdc );
162 if(!dc) return FALSE;
164 if(dc->funcs->pArcTo)
166 result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
167 xstart, ystart, xend, yend );
168 GDI_ReleaseObj( hdc );
169 return result;
171 GDI_ReleaseObj( hdc );
173 * Else emulate it.
174 * According to the documentation, a line is drawn from the current
175 * position to the starting point of the arc.
177 LineTo(hdc, xstart, ystart);
179 * Then the arc is drawn.
181 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
183 * If no error occurred, the current position is moved to the ending
184 * point of the arc.
186 if (result) MoveToEx(hdc, xend, yend, NULL);
187 return result;
190 /***********************************************************************
191 * Pie (GDI.26)
193 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
194 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
195 INT16 xend, INT16 yend )
197 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
198 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
199 (INT)yend );
203 /***********************************************************************
204 * Pie (GDI32.@)
206 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
207 INT right, INT bottom, INT xstart, INT ystart,
208 INT xend, INT yend )
210 BOOL ret = FALSE;
211 DC * dc = DC_GetDCUpdate( hdc );
212 if (!dc) return FALSE;
214 if(PATH_IsPathOpen(dc->path))
215 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
216 else if(dc->funcs->pPie)
217 ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
219 GDI_ReleaseObj( hdc );
220 return ret;
224 /***********************************************************************
225 * Chord (GDI.348)
227 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
228 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
229 INT16 xend, INT16 yend )
231 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
235 /***********************************************************************
236 * Chord (GDI32.@)
238 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
239 INT right, INT bottom, INT xstart, INT ystart,
240 INT xend, INT yend )
242 BOOL ret = FALSE;
243 DC * dc = DC_GetDCUpdate( hdc );
244 if (!dc) return FALSE;
246 if(PATH_IsPathOpen(dc->path))
247 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
248 else if(dc->funcs->pChord)
249 ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
251 GDI_ReleaseObj( hdc );
252 return ret;
256 /***********************************************************************
257 * Ellipse (GDI.24)
259 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
260 INT16 right, INT16 bottom )
262 return Ellipse( hdc, left, top, right, bottom );
266 /***********************************************************************
267 * Ellipse (GDI32.@)
269 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
270 INT right, INT bottom )
272 BOOL ret = FALSE;
273 DC * dc = DC_GetDCUpdate( hdc );
274 if (!dc) return FALSE;
276 if(PATH_IsPathOpen(dc->path))
277 ret = PATH_Ellipse(dc,left,top,right,bottom);
278 else if (dc->funcs->pEllipse)
279 ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
281 GDI_ReleaseObj( hdc );
282 return ret;
286 /***********************************************************************
287 * Rectangle (GDI.27)
289 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
290 INT16 right, INT16 bottom )
292 return Rectangle( hdc, left, top, right, bottom );
296 /***********************************************************************
297 * Rectangle (GDI32.@)
299 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
300 INT right, INT bottom )
302 BOOL ret = FALSE;
303 DC * dc = DC_GetDCUpdate( hdc );
304 if (dc)
306 if(PATH_IsPathOpen(dc->path))
307 ret = PATH_Rectangle(dc, left, top, right, bottom);
308 else if (dc->funcs->pRectangle)
309 ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
310 GDI_ReleaseObj( hdc );
312 return ret;
316 /***********************************************************************
317 * RoundRect (GDI.28)
319 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
320 INT16 bottom, INT16 ell_width, INT16 ell_height )
322 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
326 /***********************************************************************
327 * RoundRect (GDI32.@)
329 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
330 INT bottom, INT ell_width, INT ell_height )
332 BOOL ret = FALSE;
333 DC *dc = DC_GetDCUpdate( hdc );
335 if (dc)
337 if(PATH_IsPathOpen(dc->path))
338 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
339 else if (dc->funcs->pRoundRect)
340 ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
341 GDI_ReleaseObj( hdc );
343 return ret;
346 /***********************************************************************
347 * SetPixel (GDI.31)
349 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
351 return SetPixel( hdc, x, y, color );
355 /***********************************************************************
356 * SetPixel (GDI32.@)
358 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
360 COLORREF ret = 0;
361 DC * dc = DC_GetDCUpdate( hdc );
362 if (dc)
364 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
365 GDI_ReleaseObj( hdc );
367 return ret;
370 /***********************************************************************
371 * SetPixelV (GDI32.@)
373 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
375 BOOL ret = FALSE;
376 DC * dc = DC_GetDCUpdate( hdc );
377 if (dc)
379 if (dc->funcs->pSetPixel)
381 dc->funcs->pSetPixel(dc->physDev,x,y,color);
382 ret = TRUE;
384 GDI_ReleaseObj( hdc );
386 return ret;
389 /***********************************************************************
390 * GetPixel (GDI.83)
392 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
394 return GetPixel( hdc, x, y );
398 /***********************************************************************
399 * GetPixel (GDI32.@)
401 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
403 COLORREF ret = CLR_INVALID;
404 DC * dc = DC_GetDCUpdate( hdc );
406 if (dc)
408 /* FIXME: should this be in the graphics driver? */
409 if (PtVisible( hdc, x, y ))
411 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
413 GDI_ReleaseObj( hdc );
415 return ret;
419 /******************************************************************************
420 * ChoosePixelFormat [GDI32.@]
421 * Matches a pixel format to given format
423 * PARAMS
424 * hdc [I] Device context to search for best pixel match
425 * ppfd [I] Pixel format for which a match is sought
427 * RETURNS
428 * Success: Pixel format index closest to given format
429 * Failure: 0
431 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
433 INT ret = 0;
434 DC * dc = DC_GetDCPtr( hdc );
436 TRACE("(%08x,%p)\n",hdc,ppfd);
438 if (!dc) return 0;
440 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
441 else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
443 GDI_ReleaseObj( hdc );
444 return ret;
448 /******************************************************************************
449 * SetPixelFormat [GDI32.@]
450 * Sets pixel format of device context
452 * PARAMS
453 * hdc [I] Device context to search for best pixel match
454 * iPixelFormat [I] Pixel format index
455 * ppfd [I] Pixel format for which a match is sought
457 * RETURNS STD
459 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
460 const PIXELFORMATDESCRIPTOR *ppfd)
462 INT bRet = FALSE;
463 DC * dc = DC_GetDCPtr( hdc );
465 TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
467 if (!dc) return 0;
469 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
470 else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
472 GDI_ReleaseObj( hdc );
473 return bRet;
477 /******************************************************************************
478 * GetPixelFormat [GDI32.@]
479 * Gets index of pixel format of DC
481 * PARAMETERS
482 * hdc [I] Device context whose pixel format index is sought
484 * RETURNS
485 * Success: Currently selected pixel format
486 * Failure: 0
488 INT WINAPI GetPixelFormat( HDC hdc )
490 INT ret = 0;
491 DC * dc = DC_GetDCPtr( hdc );
493 TRACE("(%08x)\n",hdc);
495 if (!dc) return 0;
497 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
498 else ret = dc->funcs->pGetPixelFormat(dc->physDev);
500 GDI_ReleaseObj( hdc );
501 return ret;
505 /******************************************************************************
506 * DescribePixelFormat [GDI32.@]
507 * Gets info about pixel format from DC
509 * PARAMS
510 * hdc [I] Device context
511 * iPixelFormat [I] Pixel format selector
512 * nBytes [I] Size of buffer
513 * ppfd [O] Pointer to structure to receive pixel format data
515 * RETURNS
516 * Success: Maximum pixel format index of the device context
517 * Failure: 0
519 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
520 LPPIXELFORMATDESCRIPTOR ppfd )
522 INT ret = 0;
523 DC * dc = DC_GetDCPtr( hdc );
525 TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
527 if (!dc) return 0;
529 if (!dc->funcs->pDescribePixelFormat)
531 FIXME(" :stub\n");
532 ppfd->nSize = nBytes;
533 ppfd->nVersion = 1;
534 ret = 3;
536 else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
538 GDI_ReleaseObj( hdc );
539 return ret;
543 /******************************************************************************
544 * SwapBuffers [GDI32.@]
545 * Exchanges front and back buffers of window
547 * PARAMS
548 * hdc [I] Device context whose buffers get swapped
550 * RETURNS STD
552 BOOL WINAPI SwapBuffers( HDC hdc )
554 INT bRet = FALSE;
555 DC * dc = DC_GetDCPtr( hdc );
557 TRACE("(%08x)\n",hdc);
559 if (!dc) return TRUE;
561 if (!dc->funcs->pSwapBuffers)
563 FIXME(" :stub\n");
564 bRet = TRUE;
566 else bRet = dc->funcs->pSwapBuffers(dc->physDev);
568 GDI_ReleaseObj( hdc );
569 return bRet;
573 /***********************************************************************
574 * PaintRgn (GDI.43)
576 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
578 return PaintRgn( hdc, hrgn );
582 /***********************************************************************
583 * PaintRgn (GDI32.@)
585 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
587 BOOL ret = FALSE;
588 DC * dc = DC_GetDCUpdate( hdc );
589 if (dc)
591 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
592 GDI_ReleaseObj( hdc );
594 return ret;
598 /***********************************************************************
599 * FillRgn (GDI.40)
601 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
603 return FillRgn( hdc, hrgn, hbrush );
607 /***********************************************************************
608 * FillRgn (GDI32.@)
610 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
612 BOOL retval = FALSE;
613 HBRUSH prevBrush;
614 DC * dc = DC_GetDCUpdate( hdc );
616 if (!dc) return FALSE;
617 if(dc->funcs->pFillRgn)
618 retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
619 else if ((prevBrush = SelectObject( hdc, hbrush )))
621 retval = PaintRgn( hdc, hrgn );
622 SelectObject( hdc, prevBrush );
624 GDI_ReleaseObj( hdc );
625 return retval;
629 /***********************************************************************
630 * FrameRgn (GDI.41)
632 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
633 INT16 nWidth, INT16 nHeight )
635 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
639 /***********************************************************************
640 * FrameRgn (GDI32.@)
642 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
643 INT nWidth, INT nHeight )
645 BOOL ret = FALSE;
646 DC *dc = DC_GetDCUpdate( hdc );
648 if (!dc) return FALSE;
649 if(dc->funcs->pFrameRgn)
650 ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
651 else
653 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
654 if (tmp)
656 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
658 FillRgn( hdc, tmp, hbrush );
659 ret = TRUE;
661 DeleteObject( tmp );
664 GDI_ReleaseObj( hdc );
665 return ret;
669 /***********************************************************************
670 * InvertRgn (GDI.42)
672 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
674 return InvertRgn( hdc, hrgn );
678 /***********************************************************************
679 * InvertRgn (GDI32.@)
681 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
683 HBRUSH prevBrush;
684 INT prevROP;
685 BOOL retval;
686 DC *dc = DC_GetDCUpdate( hdc );
687 if (!dc) return FALSE;
689 if(dc->funcs->pInvertRgn)
690 retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
691 else
693 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
694 prevROP = SetROP2( hdc, R2_NOT );
695 retval = PaintRgn( hdc, hrgn );
696 SelectObject( hdc, prevBrush );
697 SetROP2( hdc, prevROP );
699 GDI_ReleaseObj( hdc );
700 return retval;
703 /**********************************************************************
704 * Polyline (GDI.37)
706 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
708 register int i;
709 BOOL16 ret;
710 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
711 count*sizeof(POINT) );
713 if (!pt32) return FALSE;
714 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
715 ret = Polyline(hdc,pt32,count);
716 HeapFree( GetProcessHeap(), 0, pt32 );
717 return ret;
721 /**********************************************************************
722 * Polyline (GDI32.@)
724 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
726 BOOL ret = FALSE;
727 DC * dc = DC_GetDCUpdate( hdc );
728 if (dc)
730 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
731 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
732 GDI_ReleaseObj( hdc );
734 return ret;
737 /**********************************************************************
738 * PolylineTo (GDI32.@)
740 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
742 DC * dc = DC_GetDCUpdate( hdc );
743 BOOL ret = FALSE;
745 if(!dc) return FALSE;
747 if(PATH_IsPathOpen(dc->path))
748 ret = PATH_PolylineTo(dc, pt, cCount);
750 else if(dc->funcs->pPolylineTo)
751 ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
753 else { /* do it using Polyline */
754 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
755 sizeof(POINT) * (cCount + 1) );
756 if (pts)
758 pts[0].x = dc->CursPosX;
759 pts[0].y = dc->CursPosY;
760 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
761 ret = Polyline( hdc, pts, cCount + 1 );
762 HeapFree( GetProcessHeap(), 0, pts );
765 if(ret) {
766 dc->CursPosX = pt[cCount-1].x;
767 dc->CursPosY = pt[cCount-1].y;
769 GDI_ReleaseObj( hdc );
770 return ret;
773 /**********************************************************************
774 * Polygon (GDI.36)
776 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
778 register int i;
779 BOOL ret;
780 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
781 count*sizeof(POINT) );
783 if (!pt32) return FALSE;
784 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
785 ret = Polygon(hdc,pt32,count);
786 HeapFree( GetProcessHeap(), 0, pt32 );
787 return ret;
791 /**********************************************************************
792 * Polygon (GDI32.@)
794 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
796 BOOL ret = FALSE;
797 DC * dc = DC_GetDCUpdate( hdc );
798 if (dc)
800 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
801 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
802 GDI_ReleaseObj( hdc );
804 return ret;
808 /**********************************************************************
809 * PolyPolygon (GDI.450)
811 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
812 UINT16 polygons )
814 int i,nrpts;
815 LPPOINT pt32;
816 LPINT counts32;
817 BOOL16 ret;
819 nrpts=0;
820 for (i=polygons;i--;)
821 nrpts+=counts[i];
822 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
823 if(pt32 == NULL) return FALSE;
824 for (i=nrpts;i--;)
825 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
826 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
827 if(counts32 == NULL) {
828 HeapFree( GetProcessHeap(), 0, pt32 );
829 return FALSE;
831 for (i=polygons;i--;) counts32[i]=counts[i];
833 ret = PolyPolygon(hdc,pt32,counts32,polygons);
834 HeapFree( GetProcessHeap(), 0, counts32 );
835 HeapFree( GetProcessHeap(), 0, pt32 );
836 return ret;
839 /**********************************************************************
840 * PolyPolygon (GDI32.@)
842 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
843 UINT polygons )
845 BOOL ret = FALSE;
846 DC * dc = DC_GetDCUpdate( hdc );
847 if (dc)
849 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
850 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
851 GDI_ReleaseObj( hdc );
853 return ret;
856 /**********************************************************************
857 * PolyPolyline (GDI32.@)
859 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
860 DWORD polylines )
862 BOOL ret = FALSE;
863 DC * dc = DC_GetDCUpdate( hdc );
864 if (dc)
866 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
867 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
868 GDI_ReleaseObj( hdc );
870 return ret;
873 /**********************************************************************
874 * ExtFloodFill (GDI.372)
876 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
877 UINT16 fillType )
879 return ExtFloodFill( hdc, x, y, color, fillType );
883 /**********************************************************************
884 * ExtFloodFill (GDI32.@)
886 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
887 UINT fillType )
889 BOOL ret = FALSE;
890 DC * dc = DC_GetDCUpdate( hdc );
891 if (dc)
893 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
894 GDI_ReleaseObj( hdc );
896 return ret;
900 /**********************************************************************
901 * FloodFill (GDI.25)
903 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
905 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
909 /**********************************************************************
910 * FloodFill (GDI32.@)
912 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
914 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
918 /******************************************************************************
919 * PolyBezier [GDI.502]
921 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
923 int i;
924 BOOL16 ret;
925 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
926 cPoints*sizeof(POINT) );
927 if(!pt32) return FALSE;
928 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
929 ret= PolyBezier(hDc, pt32, cPoints);
930 HeapFree( GetProcessHeap(), 0, pt32 );
931 return ret;
934 /******************************************************************************
935 * PolyBezierTo [GDI.503]
937 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
939 int i;
940 BOOL16 ret;
941 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
942 cPoints*sizeof(POINT) );
943 if(!pt32) return FALSE;
944 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
945 ret= PolyBezierTo(hDc, pt32, cPoints);
946 HeapFree( GetProcessHeap(), 0, pt32 );
947 return ret;
950 /******************************************************************************
951 * PolyBezier [GDI32.@]
952 * Draws one or more Bezier curves
954 * PARAMS
955 * hDc [I] Handle to device context
956 * lppt [I] Pointer to endpoints and control points
957 * cPoints [I] Count of endpoints and control points
959 * RETURNS STD
961 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
963 BOOL ret = FALSE;
964 DC * dc = DC_GetDCUpdate( hdc );
966 if(!dc) return FALSE;
968 if(PATH_IsPathOpen(dc->path))
969 ret = PATH_PolyBezier(dc, lppt, cPoints);
970 else if (dc->funcs->pPolyBezier)
971 ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
972 else /* We'll convert it into line segments and draw them using Polyline */
974 POINT *Pts;
975 INT nOut;
977 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
979 TRACE("Pts = %p, no = %d\n", Pts, nOut);
980 ret = Polyline( dc->hSelf, Pts, nOut );
981 HeapFree( GetProcessHeap(), 0, Pts );
985 GDI_ReleaseObj( hdc );
986 return ret;
989 /******************************************************************************
990 * PolyBezierTo [GDI32.@]
991 * Draws one or more Bezier curves
993 * PARAMS
994 * hDc [I] Handle to device context
995 * lppt [I] Pointer to endpoints and control points
996 * cPoints [I] Count of endpoints and control points
998 * RETURNS STD
1000 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
1002 DC * dc = DC_GetDCUpdate( hdc );
1003 BOOL ret;
1005 if(!dc) return FALSE;
1007 if(PATH_IsPathOpen(dc->path))
1008 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
1009 else if(dc->funcs->pPolyBezierTo)
1010 ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
1011 else { /* We'll do it using PolyBezier */
1012 POINT *pt;
1013 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
1014 if(!pt) return FALSE;
1015 pt[0].x = dc->CursPosX;
1016 pt[0].y = dc->CursPosY;
1017 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
1018 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
1019 HeapFree( GetProcessHeap(), 0, pt );
1021 if(ret) {
1022 dc->CursPosX = lppt[cPoints-1].x;
1023 dc->CursPosY = lppt[cPoints-1].y;
1025 GDI_ReleaseObj( hdc );
1026 return ret;
1029 /***********************************************************************
1030 * AngleArc (GDI32.@)
1032 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1034 INT x1,y1,x2,y2, arcdir;
1035 BOOL result;
1036 DC *dc;
1038 if( (signed int)dwRadius < 0 )
1039 return FALSE;
1041 dc = DC_GetDCUpdate( hdc );
1042 if(!dc) return FALSE;
1044 if(dc->funcs->pAngleArc)
1046 result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
1048 GDI_ReleaseObj( hdc );
1049 return result;
1051 GDI_ReleaseObj( hdc );
1053 /* AngleArc always works counterclockwise */
1054 arcdir = GetArcDirection( hdc );
1055 SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
1057 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1058 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1059 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1060 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1062 LineTo( hdc, x1, y1 );
1063 if( eSweepAngle >= 0 )
1064 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1065 x1, y1, x2, y2 );
1066 else
1067 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1068 x2, y2, x1, y1 );
1070 if( result ) MoveToEx( hdc, x2, y2, NULL );
1071 SetArcDirection( hdc, arcdir );
1072 return result;
1075 /***********************************************************************
1076 * PolyDraw (GDI32.@)
1078 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1079 DWORD cCount)
1081 DC *dc;
1082 BOOL result;
1083 POINT lastmove;
1084 int i;
1086 dc = DC_GetDCUpdate( hdc );
1087 if(!dc) return FALSE;
1089 if(dc->funcs->pPolyDraw)
1091 result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
1092 GDI_ReleaseObj( hdc );
1093 return result;
1095 GDI_ReleaseObj( hdc );
1097 /* check for each bezierto if there are two more points */
1098 for( i = 0; i < cCount; i++ )
1099 if( lpbTypes[i] != PT_MOVETO &&
1100 lpbTypes[i] & PT_BEZIERTO )
1102 if( cCount < i+3 )
1103 return FALSE;
1104 else
1105 i += 2;
1108 /* if no moveto occurs, we will close the figure here */
1109 lastmove.x = dc->CursPosX;
1110 lastmove.y = dc->CursPosY;
1112 /* now let's draw */
1113 for( i = 0; i < cCount; i++ )
1115 if( lpbTypes[i] == PT_MOVETO )
1117 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1118 lastmove.x = dc->CursPosX;
1119 lastmove.y = dc->CursPosY;
1121 else if( lpbTypes[i] & PT_LINETO )
1122 LineTo( hdc, lppt[i].x, lppt[i].y );
1123 else if( lpbTypes[i] & PT_BEZIERTO )
1125 PolyBezierTo( hdc, &lppt[i], 3 );
1126 i += 2;
1128 else
1129 return FALSE;
1131 if( lpbTypes[i] & PT_CLOSEFIGURE )
1133 if( PATH_IsPathOpen( dc->path ) )
1134 CloseFigure( hdc );
1135 else
1136 LineTo( hdc, lastmove.x, lastmove.y );
1140 return TRUE;
1143 /******************************************************************
1145 * *Very* simple bezier drawing code,
1147 * It uses a recursive algorithm to divide the curve in a series
1148 * of straight line segements. Not ideal but for me sufficient.
1149 * If you are in need for something better look for some incremental
1150 * algorithm.
1152 * 7 July 1998 Rein Klazes
1156 * some macro definitions for bezier drawing
1158 * to avoid trucation errors the coordinates are
1159 * shifted upwards. When used in drawing they are
1160 * shifted down again, including correct rounding
1161 * and avoiding floating point arithmatic
1162 * 4 bits should allow 27 bits coordinates which I saw
1163 * somewere in the win32 doc's
1167 #define BEZIERSHIFTBITS 4
1168 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1169 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1170 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1171 /* maximum depth of recursion */
1172 #define BEZIERMAXDEPTH 8
1174 /* size of array to store points on */
1175 /* enough for one curve */
1176 #define BEZIER_INITBUFSIZE (150)
1178 /* calculate Bezier average, in this case the middle
1179 * correctly rounded...
1180 * */
1182 #define BEZIERMIDDLE(Mid, P1, P2) \
1183 (Mid).x=((P1).x+(P2).x + 1)/2;\
1184 (Mid).y=((P1).y+(P2).y + 1)/2;
1186 /**********************************************************
1187 * BezierCheck helper function to check
1188 * that recursion can be terminated
1189 * Points[0] and Points[3] are begin and endpoint
1190 * Points[1] and Points[2] are control points
1191 * level is the recursion depth
1192 * returns true if the recusion can be terminated
1194 static BOOL BezierCheck( int level, POINT *Points)
1196 INT dx, dy;
1197 dx=Points[3].x-Points[0].x;
1198 dy=Points[3].y-Points[0].y;
1199 if(abs(dy)<=abs(dx)){/* shallow line */
1200 /* check that control points are between begin and end */
1201 if(Points[1].x < Points[0].x){
1202 if(Points[1].x < Points[3].x)
1203 return FALSE;
1204 }else
1205 if(Points[1].x > Points[3].x)
1206 return FALSE;
1207 if(Points[2].x < Points[0].x){
1208 if(Points[2].x < Points[3].x)
1209 return FALSE;
1210 }else
1211 if(Points[2].x > Points[3].x)
1212 return FALSE;
1213 dx=BEZIERSHIFTDOWN(dx);
1214 if(!dx) return TRUE;
1215 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1216 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1217 abs(Points[2].y-Points[0].y-(dy/dx)*
1218 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1219 return FALSE;
1220 else
1221 return TRUE;
1222 }else{ /* steep line */
1223 /* check that control points are between begin and end */
1224 if(Points[1].y < Points[0].y){
1225 if(Points[1].y < Points[3].y)
1226 return FALSE;
1227 }else
1228 if(Points[1].y > Points[3].y)
1229 return FALSE;
1230 if(Points[2].y < Points[0].y){
1231 if(Points[2].y < Points[3].y)
1232 return FALSE;
1233 }else
1234 if(Points[2].y > Points[3].y)
1235 return FALSE;
1236 dy=BEZIERSHIFTDOWN(dy);
1237 if(!dy) return TRUE;
1238 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1239 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1240 abs(Points[2].x-Points[0].x-(dx/dy)*
1241 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1242 return FALSE;
1243 else
1244 return TRUE;
1248 /* Helper for GDI_Bezier.
1249 * Just handles one Bezier, so Points should point to four POINTs
1251 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1252 INT *nPtsOut, INT level )
1254 if(*nPtsOut == *dwOut) {
1255 *dwOut *= 2;
1256 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1257 *dwOut * sizeof(POINT) );
1260 if(!level || BezierCheck(level, Points)) {
1261 if(*nPtsOut == 0) {
1262 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1263 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1264 *nPtsOut = 1;
1266 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1267 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1268 (*nPtsOut) ++;
1269 } else {
1270 POINT Points2[4]; /* for the second recursive call */
1271 Points2[3]=Points[3];
1272 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1273 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1274 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1276 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1277 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1278 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1280 Points2[0]=Points[3];
1282 /* do the two halves */
1283 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1284 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1290 /***********************************************************************
1291 * GDI_Bezier [INTERNAL]
1292 * Calculate line segments that approximate -what microsoft calls- a bezier
1293 * curve.
1294 * The routine recursively divides the curve in two parts until a straight
1295 * line can be drawn
1297 * PARAMS
1299 * Points [I] Ptr to count POINTs which are the end and control points
1300 * of the set of Bezier curves to flatten.
1301 * count [I] Number of Points. Must be 3n+1.
1302 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1303 * lines+1).
1305 * RETURNS
1307 * Ptr to an array of POINTs that contain the lines that approximinate the
1308 * Beziers. The array is allocated on the process heap and it is the caller's
1309 * responsibility to HeapFree it. [this is not a particularly nice interface
1310 * but since we can't know in advance how many points will generate, the
1311 * alternative would be to call the function twice, once to determine the size
1312 * and a second time to do the work - I decided this was too much of a pain].
1314 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1316 POINT *out;
1317 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1319 if((count - 1) % 3 != 0) {
1320 ERR("Invalid no. of points\n");
1321 return NULL;
1323 *nPtsOut = 0;
1324 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1325 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1326 POINT ptBuf[4];
1327 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1328 for(i = 0; i < 4; i++) {
1329 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1330 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1332 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1334 TRACE("Produced %d points\n", *nPtsOut);
1335 return out;