Do not free the not owned error string.
[wine/multimedia.git] / graphics / painting.c
blobea3c2569bc1c1ccd6b95efdac2650c3e959f5d19
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 <stdlib.h>
12 #include "windef.h"
13 #include "wingdi.h"
14 #include "winerror.h"
15 #include "gdi.h"
16 #include "bitmap.h"
17 #include "heap.h"
18 #include "region.h"
19 #include "path.h"
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(gdi);
25 /***********************************************************************
26 * LineTo16 (GDI.19)
28 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
30 return LineTo( hdc, x, y );
34 /***********************************************************************
35 * LineTo (GDI32.249)
37 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
39 DC * dc = DC_GetDCUpdate( hdc );
40 BOOL ret;
42 if(!dc) return FALSE;
44 if(PATH_IsPathOpen(dc->path))
45 ret = PATH_LineTo(dc, x, y);
46 else
47 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc,x,y);
48 if(ret) {
49 dc->CursPosX = x;
50 dc->CursPosY = y;
52 GDI_ReleaseObj( hdc );
53 return ret;
57 /***********************************************************************
58 * MoveTo16 (GDI.20)
60 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
62 POINT pt;
64 if (!MoveToEx( (HDC)hdc, x, y, &pt )) return 0;
65 return MAKELONG(pt.x,pt.y);
69 /***********************************************************************
70 * MoveToEx16 (GDI.483)
72 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
74 POINT pt32;
76 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
77 if (pt) CONV_POINT32TO16( &pt32, pt );
78 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_GetDCPtr( hdc );
90 if(!dc) return FALSE;
92 if(pt) {
93 pt->x = dc->CursPosX;
94 pt->y = dc->CursPosY;
96 dc->CursPosX = x;
97 dc->CursPosY = y;
99 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
100 else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc,x,y);
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->path))
131 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
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) return FALSE;
202 if(PATH_IsPathOpen(dc->path))
203 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
204 else if(dc->funcs->pPie)
205 ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
207 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) return FALSE;
234 if(PATH_IsPathOpen(dc->path))
235 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
236 else if(dc->funcs->pChord)
237 ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
239 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) return FALSE;
264 if(PATH_IsPathOpen(dc->path))
265 ret = PATH_Ellipse(dc,left,top,right,bottom);
266 else if (dc->funcs->pEllipse)
267 ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
269 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->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->path))
326 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
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 = CLR_INVALID;
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->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->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->CursPosX;
747 pts[0].y = dc->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->CursPosX = pt[cCount-1].x;
755 dc->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->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->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->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->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->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->CursPosX;
1004 pt[0].y = dc->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->CursPosX = lppt[cPoints-1].x;
1011 dc->CursPosY = lppt[cPoints-1].y;
1013 GDI_ReleaseObj( hdc );
1014 return ret;
1017 /***********************************************************************
1018 * AngleArc (GDI32.5)
1020 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1022 INT x1,y1,x2,y2, arcdir;
1023 BOOL result;
1024 DC *dc;
1026 if( (signed int)dwRadius < 0 )
1027 return FALSE;
1029 dc = DC_GetDCUpdate( hdc );
1030 if(!dc) return FALSE;
1032 if(dc->funcs->pAngleArc)
1034 result = dc->funcs->pAngleArc( dc, x, y, dwRadius, eStartAngle, eSweepAngle );
1036 GDI_ReleaseObj( hdc );
1037 return result;
1039 GDI_ReleaseObj( hdc );
1041 /* AngleArc always works counterclockwise */
1042 arcdir = GetArcDirection( hdc );
1043 SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
1045 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1046 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1047 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1048 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1050 LineTo( hdc, x1, y1 );
1051 if( eSweepAngle >= 0 )
1052 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1053 x1, y1, x2, y2 );
1054 else
1055 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1056 x2, y2, x1, y1 );
1058 if( result ) MoveToEx( hdc, x2, y2, NULL );
1059 SetArcDirection( hdc, arcdir );
1060 return result;
1063 /***********************************************************************
1064 * PolyDraw (GDI32.270)
1066 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1067 DWORD cCount)
1069 DC *dc;
1070 BOOL result;
1071 POINT lastmove;
1072 int i;
1074 dc = DC_GetDCUpdate( hdc );
1075 if(!dc) return FALSE;
1077 if(dc->funcs->pPolyDraw)
1079 result = dc->funcs->pPolyDraw( dc, lppt, lpbTypes, cCount );
1080 GDI_ReleaseObj( hdc );
1081 return result;
1083 GDI_ReleaseObj( hdc );
1085 /* check for each bezierto if there are two more points */
1086 for( i = 0; i < cCount; i++ )
1087 if( lpbTypes[i] != PT_MOVETO &&
1088 lpbTypes[i] & PT_BEZIERTO )
1090 if( cCount < i+3 )
1091 return FALSE;
1092 else
1093 i += 2;
1096 /* if no moveto occurs, we will close the figure here */
1097 lastmove.x = dc->CursPosX;
1098 lastmove.y = dc->CursPosY;
1100 /* now let's draw */
1101 for( i = 0; i < cCount; i++ )
1103 if( lpbTypes[i] == PT_MOVETO )
1105 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1106 lastmove.x = dc->CursPosX;
1107 lastmove.y = dc->CursPosY;
1109 else if( lpbTypes[i] & PT_LINETO )
1110 LineTo( hdc, lppt[i].x, lppt[i].y );
1111 else if( lpbTypes[i] & PT_BEZIERTO )
1113 PolyBezierTo( hdc, &lppt[i], 3 );
1114 i += 2;
1116 else
1117 return FALSE;
1119 if( lpbTypes[i] & PT_CLOSEFIGURE )
1121 if( PATH_IsPathOpen( dc->path ) )
1122 CloseFigure( hdc );
1123 else
1124 LineTo( hdc, lastmove.x, lastmove.y );
1128 return TRUE;
1131 /******************************************************************
1133 * *Very* simple bezier drawing code,
1135 * It uses a recursive algorithm to divide the curve in a series
1136 * of straight line segements. Not ideal but for me sufficient.
1137 * If you are in need for something better look for some incremental
1138 * algorithm.
1140 * 7 July 1998 Rein Klazes
1144 * some macro definitions for bezier drawing
1146 * to avoid trucation errors the coordinates are
1147 * shifted upwards. When used in drawing they are
1148 * shifted down again, including correct rounding
1149 * and avoiding floating point arithmatic
1150 * 4 bits should allow 27 bits coordinates which I saw
1151 * somewere in the win32 doc's
1155 #define BEZIERSHIFTBITS 4
1156 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1157 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1158 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1159 /* maximum depth of recursion */
1160 #define BEZIERMAXDEPTH 8
1162 /* size of array to store points on */
1163 /* enough for one curve */
1164 #define BEZIER_INITBUFSIZE (150)
1166 /* calculate Bezier average, in this case the middle
1167 * correctly rounded...
1168 * */
1170 #define BEZIERMIDDLE(Mid, P1, P2) \
1171 (Mid).x=((P1).x+(P2).x + 1)/2;\
1172 (Mid).y=((P1).y+(P2).y + 1)/2;
1174 /**********************************************************
1175 * BezierCheck helper function to check
1176 * that recursion can be terminated
1177 * Points[0] and Points[3] are begin and endpoint
1178 * Points[1] and Points[2] are control points
1179 * level is the recursion depth
1180 * returns true if the recusion can be terminated
1182 static BOOL BezierCheck( int level, POINT *Points)
1184 INT dx, dy;
1185 dx=Points[3].x-Points[0].x;
1186 dy=Points[3].y-Points[0].y;
1187 if(abs(dy)<=abs(dx)){/* shallow line */
1188 /* check that control points are between begin and end */
1189 if(Points[1].x < Points[0].x){
1190 if(Points[1].x < Points[3].x)
1191 return FALSE;
1192 }else
1193 if(Points[1].x > Points[3].x)
1194 return FALSE;
1195 if(Points[2].x < Points[0].x){
1196 if(Points[2].x < Points[3].x)
1197 return FALSE;
1198 }else
1199 if(Points[2].x > Points[3].x)
1200 return FALSE;
1201 dx=BEZIERSHIFTDOWN(dx);
1202 if(!dx) return TRUE;
1203 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1204 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1205 abs(Points[2].y-Points[0].y-(dy/dx)*
1206 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1207 return FALSE;
1208 else
1209 return TRUE;
1210 }else{ /* steep line */
1211 /* check that control points are between begin and end */
1212 if(Points[1].y < Points[0].y){
1213 if(Points[1].y < Points[3].y)
1214 return FALSE;
1215 }else
1216 if(Points[1].y > Points[3].y)
1217 return FALSE;
1218 if(Points[2].y < Points[0].y){
1219 if(Points[2].y < Points[3].y)
1220 return FALSE;
1221 }else
1222 if(Points[2].y > Points[3].y)
1223 return FALSE;
1224 dy=BEZIERSHIFTDOWN(dy);
1225 if(!dy) return TRUE;
1226 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1227 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1228 abs(Points[2].x-Points[0].x-(dx/dy)*
1229 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1230 return FALSE;
1231 else
1232 return TRUE;
1236 /* Helper for GDI_Bezier.
1237 * Just handles one Bezier, so Points should point to four POINTs
1239 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1240 INT *nPtsOut, INT level )
1242 if(*nPtsOut == *dwOut) {
1243 *dwOut *= 2;
1244 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1245 *dwOut * sizeof(POINT) );
1248 if(!level || BezierCheck(level, Points)) {
1249 if(*nPtsOut == 0) {
1250 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1251 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1252 *nPtsOut = 1;
1254 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1255 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1256 (*nPtsOut) ++;
1257 } else {
1258 POINT Points2[4]; /* for the second recursive call */
1259 Points2[3]=Points[3];
1260 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1261 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1262 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1264 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1265 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1266 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1268 Points2[0]=Points[3];
1270 /* do the two halves */
1271 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1272 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1278 /***********************************************************************
1279 * GDI_Bezier [INTERNAL]
1280 * Calculate line segments that approximate -what microsoft calls- a bezier
1281 * curve.
1282 * The routine recursively divides the curve in two parts until a straight
1283 * line can be drawn
1285 * PARAMS
1287 * Points [I] Ptr to count POINTs which are the end and control points
1288 * of the set of Bezier curves to flatten.
1289 * count [I] Number of Points. Must be 3n+1.
1290 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1291 * lines+1).
1293 * RETURNS
1295 * Ptr to an array of POINTs that contain the lines that approximinate the
1296 * Beziers. The array is allocated on the process heap and it is the caller's
1297 * responsibility to HeapFree it. [this is not a particularly nice interface
1298 * but since we can't know in advance how many points will generate, the
1299 * alternative would be to call the function twice, once to determine the size
1300 * and a second time to do the work - I decided this was too much of a pain].
1302 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1304 POINT *out;
1305 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1307 if((count - 1) % 3 != 0) {
1308 ERR("Invalid no. of points\n");
1309 return NULL;
1311 *nPtsOut = 0;
1312 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1313 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1314 POINT ptBuf[4];
1315 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1316 for(i = 0; i < 4; i++) {
1317 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1318 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1320 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1322 TRACE("Produced %d points\n", *nPtsOut);
1323 return out;