Allocate DC objects on the process heap, and removed WIN_DC_INFO
[wine/wine64.git] / graphics / painting.c
blob7b74c5612318e915d2639a86b83c41e6b4337b7f
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 POINT16 pt;
64 if (!MoveToEx16(hdc,x,y,&pt))
65 return 0;
66 return MAKELONG(pt.x,pt.y);
70 /***********************************************************************
71 * MoveToEx16 (GDI.483)
73 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
75 POINT pt32;
77 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
78 if (pt) CONV_POINT32TO16( &pt32, pt );
79 return TRUE;
84 /***********************************************************************
85 * MoveToEx (GDI32.254)
87 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
89 BOOL ret = TRUE;
90 DC * dc = DC_GetDCUpdate( hdc );
92 if(!dc) return FALSE;
94 if(pt) {
95 pt->x = dc->CursPosX;
96 pt->y = dc->CursPosY;
98 dc->CursPosX = x;
99 dc->CursPosY = y;
101 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
102 else if (dc->funcs->pMoveToEx) ret = dc->funcs->pMoveToEx(dc,x,y,pt);
103 GDI_ReleaseObj( hdc );
104 return ret;
108 /***********************************************************************
109 * Arc16 (GDI.23)
111 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
112 INT16 bottom, INT16 xstart, INT16 ystart,
113 INT16 xend, INT16 yend )
115 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
116 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
117 (INT)yend );
121 /***********************************************************************
122 * Arc (GDI32.7)
124 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
125 INT bottom, INT xstart, INT ystart,
126 INT xend, INT yend )
128 BOOL ret = FALSE;
129 DC * dc = DC_GetDCUpdate( hdc );
130 if (dc)
132 if(PATH_IsPathOpen(dc->path))
133 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
134 else if (dc->funcs->pArc)
135 ret = dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
136 GDI_ReleaseObj( hdc );
138 return ret;
141 /***********************************************************************
142 * ArcTo (GDI32.8)
144 BOOL WINAPI ArcTo( HDC hdc,
145 INT left, INT top,
146 INT right, INT bottom,
147 INT xstart, INT ystart,
148 INT xend, INT yend )
150 BOOL result;
151 DC * dc = DC_GetDCUpdate( hdc );
152 if(!dc) return FALSE;
154 if(dc->funcs->pArcTo)
156 result = dc->funcs->pArcTo( dc, left, top, right, bottom,
157 xstart, ystart, xend, yend );
158 GDI_ReleaseObj( hdc );
159 return result;
161 GDI_ReleaseObj( hdc );
163 * Else emulate it.
164 * According to the documentation, a line is drawn from the current
165 * position to the starting point of the arc.
167 LineTo(hdc, xstart, ystart);
169 * Then the arc is drawn.
171 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
173 * If no error occured, the current position is moved to the ending
174 * point of the arc.
176 if (result) MoveToEx(hdc, xend, yend, NULL);
177 return result;
180 /***********************************************************************
181 * Pie16 (GDI.26)
183 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
184 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
185 INT16 xend, INT16 yend )
187 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
188 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
189 (INT)yend );
193 /***********************************************************************
194 * Pie (GDI32.262)
196 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
197 INT right, INT bottom, INT xstart, INT ystart,
198 INT xend, INT yend )
200 BOOL ret = FALSE;
201 DC * dc = DC_GetDCUpdate( hdc );
202 if (!dc) return FALSE;
204 if(PATH_IsPathOpen(dc->path))
205 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
206 else if(dc->funcs->pPie)
207 ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
209 GDI_ReleaseObj( hdc );
210 return ret;
214 /***********************************************************************
215 * Chord16 (GDI.348)
217 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
218 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
219 INT16 xend, INT16 yend )
221 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
225 /***********************************************************************
226 * Chord (GDI32.14)
228 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
229 INT right, INT bottom, INT xstart, INT ystart,
230 INT xend, INT yend )
232 BOOL ret = FALSE;
233 DC * dc = DC_GetDCUpdate( hdc );
234 if (!dc) return FALSE;
236 if(PATH_IsPathOpen(dc->path))
237 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
238 else if(dc->funcs->pChord)
239 ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
241 GDI_ReleaseObj( hdc );
242 return ret;
246 /***********************************************************************
247 * Ellipse16 (GDI.24)
249 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
250 INT16 right, INT16 bottom )
252 return Ellipse( hdc, left, top, right, bottom );
256 /***********************************************************************
257 * Ellipse (GDI32.75)
259 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
260 INT right, INT bottom )
262 BOOL ret = FALSE;
263 DC * dc = DC_GetDCUpdate( hdc );
264 if (!dc) return FALSE;
266 if(PATH_IsPathOpen(dc->path))
267 ret = PATH_Ellipse(dc,left,top,right,bottom);
268 else if (dc->funcs->pEllipse)
269 ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
271 GDI_ReleaseObj( hdc );
272 return ret;
276 /***********************************************************************
277 * Rectangle16 (GDI.27)
279 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
280 INT16 right, INT16 bottom )
282 return Rectangle( hdc, left, top, right, bottom );
286 /***********************************************************************
287 * Rectangle (GDI32.283)
289 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
290 INT right, INT bottom )
292 BOOL ret = FALSE;
293 DC * dc = DC_GetDCUpdate( hdc );
294 if (dc)
296 if(PATH_IsPathOpen(dc->path))
297 ret = PATH_Rectangle(dc, left, top, right, bottom);
298 else if (dc->funcs->pRectangle)
299 ret = dc->funcs->pRectangle(dc,left,top,right,bottom);
300 GDI_ReleaseObj( hdc );
302 return ret;
306 /***********************************************************************
307 * RoundRect16 (GDI.28)
309 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
310 INT16 bottom, INT16 ell_width, INT16 ell_height )
312 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
316 /***********************************************************************
317 * RoundRect (GDI32.291)
319 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
320 INT bottom, INT ell_width, INT ell_height )
322 BOOL ret = FALSE;
323 DC *dc = DC_GetDCUpdate( hdc );
325 if (dc)
327 if(PATH_IsPathOpen(dc->path))
328 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
329 else if (dc->funcs->pRoundRect)
330 ret = dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
331 GDI_ReleaseObj( hdc );
333 return ret;
336 /***********************************************************************
337 * SetPixel16 (GDI.31)
339 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
341 return SetPixel( hdc, x, y, color );
345 /***********************************************************************
346 * SetPixel (GDI32.327)
348 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
350 COLORREF ret = 0;
351 DC * dc = DC_GetDCUpdate( hdc );
352 if (dc)
354 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc,x,y,color);
355 GDI_ReleaseObj( hdc );
357 return ret;
360 /***********************************************************************
361 * SetPixelV (GDI32.329)
363 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
365 BOOL ret = FALSE;
366 DC * dc = DC_GetDCUpdate( hdc );
367 if (dc)
369 if (dc->funcs->pSetPixel)
371 dc->funcs->pSetPixel(dc,x,y,color);
372 ret = TRUE;
374 GDI_ReleaseObj( hdc );
376 return ret;
379 /***********************************************************************
380 * GetPixel16 (GDI.83)
382 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
384 return GetPixel( hdc, x, y );
388 /***********************************************************************
389 * GetPixel (GDI32.211)
391 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
393 COLORREF ret = 0;
394 DC * dc = DC_GetDCUpdate( hdc );
396 if (dc)
398 /* FIXME: should this be in the graphics driver? */
399 if (PtVisible( hdc, x, y ))
401 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc,x,y);
403 GDI_ReleaseObj( hdc );
405 return ret;
409 /******************************************************************************
410 * ChoosePixelFormat [GDI32.13]
411 * Matches a pixel format to given format
413 * PARAMS
414 * hdc [I] Device context to search for best pixel match
415 * ppfd [I] Pixel format for which a match is sought
417 * RETURNS
418 * Success: Pixel format index closest to given format
419 * Failure: 0
421 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
423 INT ret = 0;
424 DC * dc = DC_GetDCPtr( hdc );
426 TRACE("(%08x,%p)\n",hdc,ppfd);
428 if (!dc) return 0;
430 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
431 else ret = dc->funcs->pChoosePixelFormat(dc,ppfd);
433 GDI_ReleaseObj( hdc );
434 return ret;
438 /******************************************************************************
439 * SetPixelFormat [GDI32.328]
440 * Sets pixel format of device context
442 * PARAMS
443 * hdc [I] Device context to search for best pixel match
444 * iPixelFormat [I] Pixel format index
445 * ppfd [I] Pixel format for which a match is sought
447 * RETURNS STD
449 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
450 const PIXELFORMATDESCRIPTOR *ppfd)
452 INT bRet = FALSE;
453 DC * dc = DC_GetDCPtr( hdc );
455 TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
457 if (!dc) return 0;
459 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
460 else bRet = dc->funcs->pSetPixelFormat(dc,iPixelFormat,ppfd);
462 GDI_ReleaseObj( hdc );
463 return bRet;
467 /******************************************************************************
468 * GetPixelFormat [GDI32.212]
469 * Gets index of pixel format of DC
471 * PARAMETERS
472 * hdc [I] Device context whose pixel format index is sought
474 * RETURNS
475 * Success: Currently selected pixel format
476 * Failure: 0
478 INT WINAPI GetPixelFormat( HDC hdc )
480 INT ret = 0;
481 DC * dc = DC_GetDCPtr( hdc );
483 TRACE("(%08x)\n",hdc);
485 if (!dc) return 0;
487 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
488 else ret = dc->funcs->pGetPixelFormat(dc);
490 GDI_ReleaseObj( hdc );
491 return ret;
495 /******************************************************************************
496 * DescribePixelFormat [GDI32.71]
497 * Gets info about pixel format from DC
499 * PARAMS
500 * hdc [I] Device context
501 * iPixelFormat [I] Pixel format selector
502 * nBytes [I] Size of buffer
503 * ppfd [O] Pointer to structure to receive pixel format data
505 * RETURNS
506 * Success: Maximum pixel format index of the device context
507 * Failure: 0
509 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
510 LPPIXELFORMATDESCRIPTOR ppfd )
512 INT ret = 0;
513 DC * dc = DC_GetDCPtr( hdc );
515 TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
517 if (!dc) return 0;
519 if (!dc->funcs->pDescribePixelFormat)
521 FIXME(" :stub\n");
522 ppfd->nSize = nBytes;
523 ppfd->nVersion = 1;
524 ret = 3;
526 else ret = dc->funcs->pDescribePixelFormat(dc,iPixelFormat,nBytes,ppfd);
528 GDI_ReleaseObj( hdc );
529 return ret;
533 /******************************************************************************
534 * SwapBuffers [GDI32.354]
535 * Exchanges front and back buffers of window
537 * PARAMS
538 * hdc [I] Device context whose buffers get swapped
540 * RETURNS STD
542 BOOL WINAPI SwapBuffers( HDC hdc )
544 INT bRet = FALSE;
545 DC * dc = DC_GetDCPtr( hdc );
547 TRACE("(%08x)\n",hdc);
549 if (!dc) return TRUE;
551 if (!dc->funcs->pSwapBuffers)
553 FIXME(" :stub\n");
554 bRet = TRUE;
556 else bRet = dc->funcs->pSwapBuffers(dc);
558 GDI_ReleaseObj( hdc );
559 return bRet;
563 /***********************************************************************
564 * PaintRgn16 (GDI.43)
566 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
568 return PaintRgn( hdc, hrgn );
572 /***********************************************************************
573 * PaintRgn (GDI32.259)
575 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
577 BOOL ret = FALSE;
578 DC * dc = DC_GetDCUpdate( hdc );
579 if (dc)
581 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc,hrgn);
582 GDI_ReleaseObj( hdc );
584 return ret;
588 /***********************************************************************
589 * FillRgn16 (GDI.40)
591 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
593 return FillRgn( hdc, hrgn, hbrush );
597 /***********************************************************************
598 * FillRgn (GDI32.101)
600 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
602 BOOL retval = FALSE;
603 HBRUSH prevBrush;
604 DC * dc = DC_GetDCUpdate( hdc );
606 if (!dc) return FALSE;
607 if(dc->funcs->pFillRgn)
608 retval = dc->funcs->pFillRgn(dc, hrgn, hbrush);
609 else if ((prevBrush = SelectObject( hdc, hbrush )))
611 retval = PaintRgn( hdc, hrgn );
612 SelectObject( hdc, prevBrush );
614 GDI_ReleaseObj( hdc );
615 return retval;
619 /***********************************************************************
620 * FrameRgn16 (GDI.41)
622 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
623 INT16 nWidth, INT16 nHeight )
625 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
629 /***********************************************************************
630 * FrameRgn (GDI32.105)
632 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
633 INT nWidth, INT nHeight )
635 BOOL ret = FALSE;
636 DC *dc = DC_GetDCUpdate( hdc );
638 if (!dc) return FALSE;
639 if(dc->funcs->pFrameRgn)
640 ret = dc->funcs->pFrameRgn( dc, hrgn, hbrush, nWidth, nHeight );
641 else
643 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
644 if (tmp)
646 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
648 FillRgn( hdc, tmp, hbrush );
649 ret = TRUE;
651 DeleteObject( tmp );
654 GDI_ReleaseObj( hdc );
655 return ret;
659 /***********************************************************************
660 * InvertRgn16 (GDI.42)
662 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
664 return InvertRgn( hdc, hrgn );
668 /***********************************************************************
669 * InvertRgn (GDI32.246)
671 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
673 HBRUSH prevBrush;
674 INT prevROP;
675 BOOL retval;
676 DC *dc = DC_GetDCUpdate( hdc );
677 if (!dc) return FALSE;
679 if(dc->funcs->pInvertRgn)
680 retval = dc->funcs->pInvertRgn( dc, hrgn );
681 else
683 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
684 prevROP = SetROP2( hdc, R2_NOT );
685 retval = PaintRgn( hdc, hrgn );
686 SelectObject( hdc, prevBrush );
687 SetROP2( hdc, prevROP );
689 GDI_ReleaseObj( hdc );
690 return retval;
693 /**********************************************************************
694 * Polyline16 (GDI.37)
696 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
698 register int i;
699 BOOL16 ret;
700 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
701 count*sizeof(POINT) );
703 if (!pt32) return FALSE;
704 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
705 ret = Polyline(hdc,pt32,count);
706 HeapFree( GetProcessHeap(), 0, pt32 );
707 return ret;
711 /**********************************************************************
712 * Polyline (GDI32.276)
714 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
716 BOOL ret = FALSE;
717 DC * dc = DC_GetDCUpdate( hdc );
718 if (dc)
720 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
721 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc,pt,count);
722 GDI_ReleaseObj( hdc );
724 return ret;
727 /**********************************************************************
728 * PolylineTo (GDI32.277)
730 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
732 DC * dc = DC_GetDCUpdate( hdc );
733 BOOL ret = FALSE;
735 if(!dc) return FALSE;
737 if(PATH_IsPathOpen(dc->path))
738 ret = PATH_PolylineTo(dc, pt, cCount);
740 else if(dc->funcs->pPolylineTo)
741 ret = dc->funcs->pPolylineTo(dc, pt, cCount);
743 else { /* do it using Polyline */
744 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
745 sizeof(POINT) * (cCount + 1) );
746 if (pts)
748 pts[0].x = dc->CursPosX;
749 pts[0].y = dc->CursPosY;
750 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
751 ret = Polyline( hdc, pts, cCount + 1 );
752 HeapFree( GetProcessHeap(), 0, pts );
755 if(ret) {
756 dc->CursPosX = pt[cCount-1].x;
757 dc->CursPosY = pt[cCount-1].y;
759 GDI_ReleaseObj( hdc );
760 return ret;
763 /**********************************************************************
764 * Polygon16 (GDI.36)
766 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
768 register int i;
769 BOOL ret;
770 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
771 count*sizeof(POINT) );
773 if (!pt32) return FALSE;
774 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
775 ret = Polygon(hdc,pt32,count);
776 HeapFree( GetProcessHeap(), 0, pt32 );
777 return ret;
781 /**********************************************************************
782 * Polygon (GDI32.275)
784 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
786 BOOL ret = FALSE;
787 DC * dc = DC_GetDCUpdate( hdc );
788 if (dc)
790 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
791 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc,pt,count);
792 GDI_ReleaseObj( hdc );
794 return ret;
798 /**********************************************************************
799 * PolyPolygon16 (GDI.450)
801 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
802 UINT16 polygons )
804 int i,nrpts;
805 LPPOINT pt32;
806 LPINT counts32;
807 BOOL16 ret;
809 nrpts=0;
810 for (i=polygons;i--;)
811 nrpts+=counts[i];
812 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
813 if(pt32 == NULL) return FALSE;
814 for (i=nrpts;i--;)
815 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
816 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
817 if(counts32 == NULL) {
818 HeapFree( GetProcessHeap(), 0, pt32 );
819 return FALSE;
821 for (i=polygons;i--;) counts32[i]=counts[i];
823 ret = PolyPolygon(hdc,pt32,counts32,polygons);
824 HeapFree( GetProcessHeap(), 0, counts32 );
825 HeapFree( GetProcessHeap(), 0, pt32 );
826 return ret;
829 /**********************************************************************
830 * PolyPolygon (GDI.450)
832 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
833 UINT polygons )
835 BOOL ret = FALSE;
836 DC * dc = DC_GetDCUpdate( hdc );
837 if (dc)
839 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
840 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
841 GDI_ReleaseObj( hdc );
843 return ret;
846 /**********************************************************************
847 * PolyPolyline (GDI32.272)
849 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
850 DWORD polylines )
852 BOOL ret = FALSE;
853 DC * dc = DC_GetDCUpdate( hdc );
854 if (dc)
856 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
857 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
858 GDI_ReleaseObj( hdc );
860 return ret;
863 /**********************************************************************
864 * ExtFloodFill16 (GDI.372)
866 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
867 UINT16 fillType )
869 return ExtFloodFill( hdc, x, y, color, fillType );
873 /**********************************************************************
874 * ExtFloodFill (GDI32.96)
876 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
877 UINT fillType )
879 BOOL ret = FALSE;
880 DC * dc = DC_GetDCUpdate( hdc );
881 if (dc)
883 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
884 GDI_ReleaseObj( hdc );
886 return ret;
890 /**********************************************************************
891 * FloodFill16 (GDI.25)
893 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
895 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
899 /**********************************************************************
900 * FloodFill (GDI32.104)
902 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
904 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
908 /******************************************************************************
909 * PolyBezier16 [GDI.502]
911 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
913 int i;
914 BOOL16 ret;
915 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
916 cPoints*sizeof(POINT) );
917 if(!pt32) return FALSE;
918 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
919 ret= PolyBezier(hDc, pt32, cPoints);
920 HeapFree( GetProcessHeap(), 0, pt32 );
921 return ret;
924 /******************************************************************************
925 * PolyBezierTo16 [GDI.503]
927 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
929 int i;
930 BOOL16 ret;
931 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
932 cPoints*sizeof(POINT) );
933 if(!pt32) return FALSE;
934 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
935 ret= PolyBezierTo(hDc, pt32, cPoints);
936 HeapFree( GetProcessHeap(), 0, pt32 );
937 return ret;
940 /******************************************************************************
941 * PolyBezier [GDI32.268]
942 * Draws one or more Bezier curves
944 * PARAMS
945 * hDc [I] Handle to device context
946 * lppt [I] Pointer to endpoints and control points
947 * cPoints [I] Count of endpoints and control points
949 * RETURNS STD
951 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
953 BOOL ret = FALSE;
954 DC * dc = DC_GetDCUpdate( hdc );
956 if(!dc) return FALSE;
958 if(PATH_IsPathOpen(dc->path))
959 ret = PATH_PolyBezier(dc, lppt, cPoints);
960 else if (dc->funcs->pPolyBezier)
961 ret = dc->funcs->pPolyBezier(dc, lppt, cPoints);
962 else /* We'll convert it into line segments and draw them using Polyline */
964 POINT *Pts;
965 INT nOut;
967 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
969 TRACE("Pts = %p, no = %d\n", Pts, nOut);
970 ret = Polyline( dc->hSelf, Pts, nOut );
971 HeapFree( GetProcessHeap(), 0, Pts );
975 GDI_ReleaseObj( hdc );
976 return ret;
979 /******************************************************************************
980 * PolyBezierTo [GDI32.269]
981 * Draws one or more Bezier curves
983 * PARAMS
984 * hDc [I] Handle to device context
985 * lppt [I] Pointer to endpoints and control points
986 * cPoints [I] Count of endpoints and control points
988 * RETURNS STD
990 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
992 DC * dc = DC_GetDCUpdate( hdc );
993 BOOL ret;
995 if(!dc) return FALSE;
997 if(PATH_IsPathOpen(dc->path))
998 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
999 else if(dc->funcs->pPolyBezierTo)
1000 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
1001 else { /* We'll do it using PolyBezier */
1002 POINT *pt;
1003 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
1004 if(!pt) return FALSE;
1005 pt[0].x = dc->CursPosX;
1006 pt[0].y = dc->CursPosY;
1007 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
1008 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
1009 HeapFree( GetProcessHeap(), 0, pt );
1011 if(ret) {
1012 dc->CursPosX = lppt[cPoints-1].x;
1013 dc->CursPosY = lppt[cPoints-1].y;
1015 GDI_ReleaseObj( hdc );
1016 return ret;
1019 /***********************************************************************
1020 * AngleArc (GDI32.5)
1022 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1024 INT x1,y1,x2,y2, arcdir;
1025 BOOL result;
1026 DC *dc;
1028 if( (signed int)dwRadius < 0 )
1029 return FALSE;
1031 dc = DC_GetDCUpdate( hdc );
1032 if(!dc) return FALSE;
1034 if(dc->funcs->pAngleArc)
1036 result = dc->funcs->pAngleArc( dc, x, y, dwRadius, eStartAngle, eSweepAngle );
1038 GDI_ReleaseObj( hdc );
1039 return result;
1041 GDI_ReleaseObj( hdc );
1043 /* AngleArc always works counterclockwise */
1044 arcdir = GetArcDirection( hdc );
1045 SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
1047 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1048 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1049 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1050 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1052 LineTo( hdc, x1, y1 );
1053 if( eSweepAngle >= 0 )
1054 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1055 x1, y1, x2, y2 );
1056 else
1057 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1058 x2, y2, x1, y1 );
1060 if( result ) MoveToEx( hdc, x2, y2, NULL );
1061 SetArcDirection( hdc, arcdir );
1062 return result;
1065 /***********************************************************************
1066 * PolyDraw (GDI32.270)
1068 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1069 DWORD cCount)
1071 DC *dc;
1072 BOOL result;
1073 POINT lastmove;
1074 int i;
1076 dc = DC_GetDCUpdate( hdc );
1077 if(!dc) return FALSE;
1079 if(dc->funcs->pPolyDraw)
1081 result = dc->funcs->pPolyDraw( dc, lppt, lpbTypes, cCount );
1082 GDI_ReleaseObj( hdc );
1083 return result;
1085 GDI_ReleaseObj( hdc );
1087 /* check for each bezierto if there are two more points */
1088 for( i = 0; i < cCount; i++ )
1089 if( lpbTypes[i] != PT_MOVETO &&
1090 lpbTypes[i] & PT_BEZIERTO )
1092 if( cCount < i+3 )
1093 return FALSE;
1094 else
1095 i += 2;
1098 /* if no moveto occurs, we will close the figure here */
1099 lastmove.x = dc->CursPosX;
1100 lastmove.y = dc->CursPosY;
1102 /* now let's draw */
1103 for( i = 0; i < cCount; i++ )
1105 if( lpbTypes[i] == PT_MOVETO )
1107 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1108 lastmove.x = dc->CursPosX;
1109 lastmove.y = dc->CursPosY;
1111 else if( lpbTypes[i] & PT_LINETO )
1112 LineTo( hdc, lppt[i].x, lppt[i].y );
1113 else if( lpbTypes[i] & PT_BEZIERTO )
1115 PolyBezierTo( hdc, &lppt[i], 3 );
1116 i += 2;
1118 else
1119 return FALSE;
1121 if( lpbTypes[i] & PT_CLOSEFIGURE )
1123 if( PATH_IsPathOpen( dc->path ) )
1124 CloseFigure( hdc );
1125 else
1126 LineTo( hdc, lastmove.x, lastmove.y );
1130 return TRUE;
1133 /******************************************************************
1135 * *Very* simple bezier drawing code,
1137 * It uses a recursive algorithm to divide the curve in a series
1138 * of straight line segements. Not ideal but for me sufficient.
1139 * If you are in need for something better look for some incremental
1140 * algorithm.
1142 * 7 July 1998 Rein Klazes
1146 * some macro definitions for bezier drawing
1148 * to avoid trucation errors the coordinates are
1149 * shifted upwards. When used in drawing they are
1150 * shifted down again, including correct rounding
1151 * and avoiding floating point arithmatic
1152 * 4 bits should allow 27 bits coordinates which I saw
1153 * somewere in the win32 doc's
1157 #define BEZIERSHIFTBITS 4
1158 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1159 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1160 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1161 /* maximum depth of recursion */
1162 #define BEZIERMAXDEPTH 8
1164 /* size of array to store points on */
1165 /* enough for one curve */
1166 #define BEZIER_INITBUFSIZE (150)
1168 /* calculate Bezier average, in this case the middle
1169 * correctly rounded...
1170 * */
1172 #define BEZIERMIDDLE(Mid, P1, P2) \
1173 (Mid).x=((P1).x+(P2).x + 1)/2;\
1174 (Mid).y=((P1).y+(P2).y + 1)/2;
1176 /**********************************************************
1177 * BezierCheck helper function to check
1178 * that recursion can be terminated
1179 * Points[0] and Points[3] are begin and endpoint
1180 * Points[1] and Points[2] are control points
1181 * level is the recursion depth
1182 * returns true if the recusion can be terminated
1184 static BOOL BezierCheck( int level, POINT *Points)
1186 INT dx, dy;
1187 dx=Points[3].x-Points[0].x;
1188 dy=Points[3].y-Points[0].y;
1189 if(abs(dy)<=abs(dx)){/* shallow line */
1190 /* check that control points are between begin and end */
1191 if(Points[1].x < Points[0].x){
1192 if(Points[1].x < Points[3].x)
1193 return FALSE;
1194 }else
1195 if(Points[1].x > Points[3].x)
1196 return FALSE;
1197 if(Points[2].x < Points[0].x){
1198 if(Points[2].x < Points[3].x)
1199 return FALSE;
1200 }else
1201 if(Points[2].x > Points[3].x)
1202 return FALSE;
1203 dx=BEZIERSHIFTDOWN(dx);
1204 if(!dx) return TRUE;
1205 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1206 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1207 abs(Points[2].y-Points[0].y-(dy/dx)*
1208 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1209 return FALSE;
1210 else
1211 return TRUE;
1212 }else{ /* steep line */
1213 /* check that control points are between begin and end */
1214 if(Points[1].y < Points[0].y){
1215 if(Points[1].y < Points[3].y)
1216 return FALSE;
1217 }else
1218 if(Points[1].y > Points[3].y)
1219 return FALSE;
1220 if(Points[2].y < Points[0].y){
1221 if(Points[2].y < Points[3].y)
1222 return FALSE;
1223 }else
1224 if(Points[2].y > Points[3].y)
1225 return FALSE;
1226 dy=BEZIERSHIFTDOWN(dy);
1227 if(!dy) return TRUE;
1228 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1229 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1230 abs(Points[2].x-Points[0].x-(dx/dy)*
1231 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1232 return FALSE;
1233 else
1234 return TRUE;
1238 /* Helper for GDI_Bezier.
1239 * Just handles one Bezier, so Points should point to four POINTs
1241 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1242 INT *nPtsOut, INT level )
1244 if(*nPtsOut == *dwOut) {
1245 *dwOut *= 2;
1246 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1247 *dwOut * sizeof(POINT) );
1250 if(!level || BezierCheck(level, Points)) {
1251 if(*nPtsOut == 0) {
1252 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1253 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1254 *nPtsOut = 1;
1256 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1257 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1258 (*nPtsOut) ++;
1259 } else {
1260 POINT Points2[4]; /* for the second recursive call */
1261 Points2[3]=Points[3];
1262 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1263 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1264 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1266 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1267 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1268 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1270 Points2[0]=Points[3];
1272 /* do the two halves */
1273 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1274 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1280 /***********************************************************************
1281 * GDI_Bezier [INTERNAL]
1282 * Calculate line segments that approximate -what microsoft calls- a bezier
1283 * curve.
1284 * The routine recursively divides the curve in two parts until a straight
1285 * line can be drawn
1287 * PARAMS
1289 * Points [I] Ptr to count POINTs which are the end and control points
1290 * of the set of Bezier curves to flatten.
1291 * count [I] Number of Points. Must be 3n+1.
1292 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1293 * lines+1).
1295 * RETURNS
1297 * Ptr to an array of POINTs that contain the lines that approximinate the
1298 * Beziers. The array is allocated on the process heap and it is the caller's
1299 * responsibility to HeapFree it. [this is not a particularly nice interface
1300 * but since we can't know in advance how many points will generate, the
1301 * alternative would be to call the function twice, once to determine the size
1302 * and a second time to do the work - I decided this was too much of a pain].
1304 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1306 POINT *out;
1307 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1309 if((count - 1) % 3 != 0) {
1310 ERR("Invalid no. of points\n");
1311 return NULL;
1313 *nPtsOut = 0;
1314 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1315 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1316 POINT ptBuf[4];
1317 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1318 for(i = 0; i < 4; i++) {
1319 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1320 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1322 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1324 TRACE("Produced %d points\n", *nPtsOut);
1325 return out;