Encapsulated Wine internal data into an ifdef __WINE__.
[wine.git] / graphics / painting.c
blob049583ee5877ad93ba2734fdcfafce461c63a8cb
1 /*
2 * GDI drawing functions.
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
6 * 1999 Huw D M Davies
7 */
9 #include <string.h>
10 #include "dc.h"
11 #include "bitmap.h"
12 #include "heap.h"
13 #include "monitor.h"
14 #include "cache.h"
15 #include "region.h"
16 #include "path.h"
17 #include "debugtools.h"
18 #include "winerror.h"
19 #include "winuser.h"
20 #include "wine/winuser16.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_GetDCPtr( hdc );
40 BOOL ret;
42 if(!dc) return FALSE;
44 if(PATH_IsPathOpen(dc->w.path))
45 ret = PATH_LineTo(hdc, x, y);
46 else
47 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc,x,y);
48 if(ret) {
49 dc->w.CursPosX = x;
50 dc->w.CursPosY = y;
52 return ret;
56 /***********************************************************************
57 * MoveTo16 (GDI.20)
59 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
61 POINT16 pt;
63 if (!MoveToEx16(hdc,x,y,&pt))
64 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;
83 /***********************************************************************
84 * MoveToEx (GDI32.254)
86 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
88 DC * dc = DC_GetDCPtr( hdc );
90 if(!dc) return FALSE;
92 if(pt) {
93 pt->x = dc->w.CursPosX;
94 pt->y = dc->w.CursPosY;
96 dc->w.CursPosX = x;
97 dc->w.CursPosY = y;
99 if(PATH_IsPathOpen(dc->w.path))
100 return PATH_MoveTo(hdc);
102 if(dc->funcs->pMoveToEx)
103 return dc->funcs->pMoveToEx(dc,x,y,pt);
104 return FALSE;
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 DC * dc = DC_GetDCPtr( hdc );
129 if(!dc) return FALSE;
131 if(PATH_IsPathOpen(dc->w.path))
132 return PATH_Arc(hdc, left, top, right, bottom, xstart, ystart, xend,
133 yend);
135 return dc->funcs->pArc &&
136 dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
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_GetDCPtr( hdc );
150 if(!dc) return FALSE;
152 if(dc->funcs->pArcTo)
153 return dc->funcs->pArcTo( dc, left, top, right, bottom,
154 xstart, ystart, xend, yend );
156 * Else emulate it.
157 * According to the documentation, a line is drawn from the current
158 * position to the starting point of the arc.
160 LineTo(hdc, xstart, ystart);
163 * Then the arc is drawn.
165 result = Arc(hdc,
166 left, top,
167 right, bottom,
168 xstart, ystart,
169 xend, yend);
172 * If no error occured, the current position is moved to the ending
173 * point of the arc.
175 if (result)
177 MoveToEx(hdc, xend, yend, NULL);
180 return result;
183 /***********************************************************************
184 * Pie16 (GDI.26)
186 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
187 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
188 INT16 xend, INT16 yend )
190 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
191 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
192 (INT)yend );
196 /***********************************************************************
197 * Pie (GDI32.262)
199 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
200 INT right, INT bottom, INT xstart, INT ystart,
201 INT xend, INT yend )
203 DC * dc = DC_GetDCPtr( hdc );
204 if(!dc) return FALSE;
206 if(PATH_IsPathOpen(dc->w.path)) {
207 FIXME("-> Path: stub\n");
208 return FALSE;
211 return dc->funcs->pPie &&
212 dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
216 /***********************************************************************
217 * Chord16 (GDI.348)
219 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
220 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
221 INT16 xend, INT16 yend )
223 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
227 /***********************************************************************
228 * Chord (GDI32.14)
230 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
231 INT right, INT bottom, INT xstart, INT ystart,
232 INT xend, INT yend )
234 DC * dc = DC_GetDCPtr( hdc );
235 if(!dc) return FALSE;
237 if(PATH_IsPathOpen(dc->w.path)) {
238 FIXME("-> Path: stub\n");
239 return FALSE;
242 return dc->funcs->pChord &&
243 dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
247 /***********************************************************************
248 * Ellipse16 (GDI.24)
250 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
251 INT16 right, INT16 bottom )
253 return Ellipse( hdc, left, top, right, bottom );
257 /***********************************************************************
258 * Ellipse (GDI32.75)
260 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
261 INT right, INT bottom )
263 DC * dc = DC_GetDCPtr( hdc );
264 if(!dc) return FALSE;
266 if(PATH_IsPathOpen(dc->w.path)) {
267 FIXME("-> Path: stub\n");
268 return FALSE;
271 return dc->funcs->pEllipse &&
272 dc->funcs->pEllipse(dc,left,top,right,bottom);
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 DC * dc = DC_GetDCPtr( hdc );
293 if(!dc) return FALSE;
295 if(PATH_IsPathOpen(dc->w.path))
296 return PATH_Rectangle(hdc, left, top, right, bottom);
298 return dc->funcs->pRectangle &&
299 dc->funcs->pRectangle(dc,left,top,right,bottom);
303 /***********************************************************************
304 * RoundRect16 (GDI.28)
306 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
307 INT16 bottom, INT16 ell_width, INT16 ell_height )
309 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
313 /***********************************************************************
314 * RoundRect (GDI32.291)
316 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
317 INT bottom, INT ell_width, INT ell_height )
319 DC * dc = DC_GetDCPtr( hdc );
320 if(!dc) return FALSE;
322 if(PATH_IsPathOpen(dc->w.path)) {
323 FIXME("-> Path: stub\n");
324 return FALSE;
327 return dc->funcs->pRoundRect &&
328 dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
331 /***********************************************************************
332 * SetPixel16 (GDI.31)
334 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
336 return SetPixel( hdc, x, y, color );
340 /***********************************************************************
341 * SetPixel (GDI32.327)
343 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
345 DC * dc = DC_GetDCPtr( hdc );
347 if (!dc || !dc->funcs->pSetPixel) return 0;
348 return dc->funcs->pSetPixel(dc,x,y,color);
351 /***********************************************************************
352 * SetPixelV (GDI32.329)
354 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
356 DC * dc = DC_GetDCPtr( hdc );
358 if (!dc || !dc->funcs->pSetPixel) return FALSE;
359 dc->funcs->pSetPixel(dc,x,y,color);
360 return TRUE;
363 /***********************************************************************
364 * GetPixel16 (GDI.83)
366 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
368 return GetPixel( hdc, x, y );
372 /***********************************************************************
373 * GetPixel (GDI32.211)
375 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
377 DC * dc = DC_GetDCPtr( hdc );
379 if (!dc) return 0;
380 #ifdef SOLITAIRE_SPEED_HACK
381 return 0;
382 #endif
384 /* FIXME: should this be in the graphics driver? */
385 if (!PtVisible( hdc, x, y )) return 0;
386 if (!dc || !dc->funcs->pGetPixel) return 0;
387 return dc->funcs->pGetPixel(dc,x,y);
391 /******************************************************************************
392 * ChoosePixelFormat [GDI32.13]
393 * Matches a pixel format to given format
395 * PARAMS
396 * hdc [I] Device context to search for best pixel match
397 * ppfd [I] Pixel format for which a match is sought
399 * RETURNS
400 * Success: Pixel format index closest to given format
401 * Failure: 0
403 INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
405 FIXME("(%d,%p): stub\n",hdc,ppfd);
406 return 1;
410 /******************************************************************************
411 * SetPixelFormat [GDI32.328]
412 * Sets pixel format of device context
414 * PARAMS
415 * hdc [I] Device context to search for best pixel match
416 * iPixelFormat [I] Pixel format index
417 * ppfd [I] Pixel format for which a match is sought
419 * RETURNS STD
421 BOOL WINAPI SetPixelFormat( HDC hdc, int iPixelFormat,
422 const PIXELFORMATDESCRIPTOR* ppfd)
424 FIXME("(%d,%d,%p): stub\n",hdc,iPixelFormat,ppfd);
425 return TRUE;
429 /******************************************************************************
430 * GetPixelFormat [GDI32.212]
431 * Gets index of pixel format of DC
433 * PARAMETERS
434 * hdc [I] Device context whose pixel format index is sought
436 * RETURNS
437 * Success: Currently selected pixel format
438 * Failure: 0
440 int WINAPI GetPixelFormat( HDC hdc )
442 FIXME("(%d): stub\n",hdc);
443 return 1;
447 /******************************************************************************
448 * DescribePixelFormat [GDI32.71]
449 * Gets info about pixel format from DC
451 * PARAMS
452 * hdc [I] Device context
453 * iPixelFormat [I] Pixel format selector
454 * nBytes [I] Size of buffer
455 * ppfd [O] Pointer to structure to receive pixel format data
457 * RETURNS
458 * Success: Maximum pixel format index of the device context
459 * Failure: 0
461 int WINAPI DescribePixelFormat( HDC hdc, int iPixelFormat, UINT nBytes,
462 LPPIXELFORMATDESCRIPTOR ppfd )
464 FIXME("(%d,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
465 ppfd->nSize = nBytes;
466 ppfd->nVersion = 1;
467 return 3;
471 /******************************************************************************
472 * SwapBuffers [GDI32.354]
473 * Exchanges front and back buffers of window
475 * PARAMS
476 * hdc [I] Device context whose buffers get swapped
478 * RETURNS STD
480 BOOL WINAPI SwapBuffers( HDC hdc )
482 FIXME("(%d): stub\n",hdc);
483 return TRUE;
487 /***********************************************************************
488 * PaintRgn16 (GDI.43)
490 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
492 return PaintRgn( hdc, hrgn );
496 /***********************************************************************
497 * PaintRgn (GDI32.259)
499 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
501 DC * dc = DC_GetDCPtr( hdc );
503 return dc && dc->funcs->pPaintRgn &&
504 dc->funcs->pPaintRgn(dc,hrgn);
508 /***********************************************************************
509 * FillRgn16 (GDI.40)
511 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
513 return FillRgn( hdc, hrgn, hbrush );
517 /***********************************************************************
518 * FillRgn (GDI32.101)
520 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
522 BOOL retval;
523 HBRUSH prevBrush;
524 DC * dc = DC_GetDCPtr( hdc );
526 if (!dc) return FALSE;
527 if(dc->funcs->pFillRgn)
528 return dc->funcs->pFillRgn(dc, hrgn, hbrush);
530 prevBrush = SelectObject( hdc, hbrush );
531 if (!prevBrush) return FALSE;
532 retval = PaintRgn( hdc, hrgn );
533 SelectObject( hdc, prevBrush );
534 return retval;
538 /***********************************************************************
539 * FrameRgn16 (GDI.41)
541 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
542 INT16 nWidth, INT16 nHeight )
544 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
548 /***********************************************************************
549 * FrameRgn (GDI32.105)
551 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
552 INT nWidth, INT nHeight )
554 HRGN tmp;
555 DC *dc = DC_GetDCPtr( hdc );
557 if(dc->funcs->pFrameRgn)
558 return dc->funcs->pFrameRgn( dc, hrgn, hbrush, nWidth, nHeight );
560 tmp = CreateRectRgn( 0, 0, 0, 0 );
561 if(!REGION_FrameRgn( tmp, hrgn, nWidth, nHeight )) return FALSE;
562 FillRgn( hdc, tmp, hbrush );
563 DeleteObject( tmp );
564 return TRUE;
568 /***********************************************************************
569 * InvertRgn16 (GDI.42)
571 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
573 return InvertRgn( hdc, hrgn );
577 /***********************************************************************
578 * InvertRgn (GDI32.246)
580 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
582 HBRUSH prevBrush;
583 INT prevROP;
584 BOOL retval;
585 DC *dc = DC_GetDCPtr( hdc );
587 if(dc->funcs->pInvertRgn)
588 return dc->funcs->pInvertRgn( dc, hrgn );
590 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
591 prevROP = SetROP2( hdc, R2_NOT );
592 retval = PaintRgn( hdc, hrgn );
593 SelectObject( hdc, prevBrush );
594 SetROP2( hdc, prevROP );
595 return retval;
598 /**********************************************************************
599 * Polyline16 (GDI.37)
601 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
603 register int i;
604 BOOL16 ret;
605 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
606 count*sizeof(POINT) );
608 if (!pt32) return FALSE;
609 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
610 ret = Polyline(hdc,pt32,count);
611 HeapFree( GetProcessHeap(), 0, pt32 );
612 return ret;
616 /**********************************************************************
617 * Polyline (GDI32.276)
619 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
621 DC * dc = DC_GetDCPtr( hdc );
622 if(!dc) return FALSE;
624 if(PATH_IsPathOpen(dc->w.path))
625 return PATH_Polyline(hdc, pt, count);
627 return dc->funcs->pPolyline &&
628 dc->funcs->pPolyline(dc,pt,count);
631 /**********************************************************************
632 * PolylineTo (GDI32.277)
634 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
636 DC * dc = DC_GetDCPtr( hdc );
637 BOOL ret;
639 if(!dc) return FALSE;
641 if(PATH_IsPathOpen(dc->w.path))
642 ret = PATH_PolylineTo(hdc, pt, cCount);
644 else if(dc->funcs->pPolylineTo)
645 ret = dc->funcs->pPolylineTo(dc, pt, cCount);
647 else { /* do it using Polyline */
648 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
649 sizeof(POINT) * (cCount + 1) );
650 if(!pts) return FALSE;
652 pts[0].x = dc->w.CursPosX;
653 pts[0].y = dc->w.CursPosY;
654 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
655 ret = Polyline( hdc, pts, cCount + 1 );
656 HeapFree( GetProcessHeap(), 0, pts );
658 if(ret) {
659 dc->w.CursPosX = pt[cCount-1].x;
660 dc->w.CursPosY = pt[cCount-1].y;
662 return ret;
665 /**********************************************************************
666 * Polygon16 (GDI.36)
668 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
670 register int i;
671 BOOL ret;
672 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
673 count*sizeof(POINT) );
675 if (!pt32) return FALSE;
676 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
677 ret = Polygon(hdc,pt32,count);
678 HeapFree( GetProcessHeap(), 0, pt32 );
679 return ret;
683 /**********************************************************************
684 * Polygon (GDI32.275)
686 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
688 DC * dc = DC_GetDCPtr( hdc );
689 if(!dc) return FALSE;
691 if(PATH_IsPathOpen(dc->w.path))
692 return PATH_Polygon(hdc, pt, count);
694 return dc->funcs->pPolygon &&
695 dc->funcs->pPolygon(dc,pt,count);
699 /**********************************************************************
700 * PolyPolygon16 (GDI.450)
702 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
703 UINT16 polygons )
705 int i,nrpts;
706 LPPOINT pt32;
707 LPINT counts32;
708 BOOL16 ret;
710 nrpts=0;
711 for (i=polygons;i--;)
712 nrpts+=counts[i];
713 pt32 = (LPPOINT)HEAP_xalloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
714 for (i=nrpts;i--;)
715 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
716 counts32 = (LPINT)HEAP_xalloc( GetProcessHeap(), 0,
717 polygons*sizeof(INT) );
718 for (i=polygons;i--;) counts32[i]=counts[i];
720 ret = PolyPolygon(hdc,pt32,counts32,polygons);
721 HeapFree( GetProcessHeap(), 0, counts32 );
722 HeapFree( GetProcessHeap(), 0, pt32 );
723 return ret;
726 /**********************************************************************
727 * PolyPolygon (GDI.450)
729 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
730 UINT polygons )
732 DC * dc = DC_GetDCPtr( hdc );
733 if(!dc) return FALSE;
735 if(PATH_IsPathOpen(dc->w.path))
736 return PATH_PolyPolygon(hdc, pt, counts, polygons);
738 return dc->funcs->pPolyPolygon &&
739 dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
742 /**********************************************************************
743 * PolyPolyline (GDI32.272)
745 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
746 DWORD polylines )
748 DC * dc = DC_GetDCPtr( hdc );
749 if(!dc) return FALSE;
751 if(PATH_IsPathOpen(dc->w.path))
752 return PATH_PolyPolyline(hdc, pt, counts, polylines);
754 return dc->funcs->pPolyPolyline &&
755 dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
758 /**********************************************************************
759 * ExtFloodFill16 (GDI.372)
761 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
762 UINT16 fillType )
764 return ExtFloodFill( hdc, x, y, color, fillType );
768 /**********************************************************************
769 * ExtFloodFill (GDI32.96)
771 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
772 UINT fillType )
774 DC *dc = DC_GetDCPtr( hdc );
776 return dc && dc->funcs->pExtFloodFill &&
777 dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
781 /**********************************************************************
782 * FloodFill16 (GDI.25)
784 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
786 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
790 /**********************************************************************
791 * FloodFill (GDI32.104)
793 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
795 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
799 /******************************************************************************
800 * PolyBezier16 [GDI.502]
802 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
804 int i;
805 BOOL16 ret;
806 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
807 cPoints*sizeof(POINT) );
808 if(!pt32) return FALSE;
809 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
810 ret= PolyBezier(hDc, pt32, cPoints);
811 HeapFree( GetProcessHeap(), 0, pt32 );
812 return ret;
815 /******************************************************************************
816 * PolyBezierTo16 [GDI.503]
818 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
820 int i;
821 BOOL16 ret;
822 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
823 cPoints*sizeof(POINT) );
824 if(!pt32) return FALSE;
825 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
826 ret= PolyBezierTo(hDc, pt32, cPoints);
827 HeapFree( GetProcessHeap(), 0, pt32 );
828 return ret;
831 /******************************************************************************
832 * PolyBezier [GDI32.268]
833 * Draws one or more Bezier curves
835 * PARAMS
836 * hDc [I] Handle to device context
837 * lppt [I] Pointer to endpoints and control points
838 * cPoints [I] Count of endpoints and control points
840 * RETURNS STD
842 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
844 DC * dc = DC_GetDCPtr( hdc );
845 if(!dc) return FALSE;
847 if(PATH_IsPathOpen(dc->w.path))
848 return PATH_PolyBezier(hdc, lppt, cPoints);
850 if(dc->funcs->pPolyBezier)
851 return dc->funcs->pPolyBezier(dc, lppt, cPoints);
853 /* We'll convert it into line segments and draw them using Polyline */
855 POINT *Pts;
856 INT nOut;
857 BOOL ret;
859 Pts = GDI_Bezier( lppt, cPoints, &nOut );
860 if(!Pts) return FALSE;
861 TRACE("Pts = %p, no = %d\n", Pts, nOut);
862 ret = Polyline( dc->hSelf, Pts, nOut );
863 HeapFree( GetProcessHeap(), 0, Pts );
864 return ret;
868 /******************************************************************************
869 * PolyBezierTo [GDI32.269]
870 * Draws one or more Bezier curves
872 * PARAMS
873 * hDc [I] Handle to device context
874 * lppt [I] Pointer to endpoints and control points
875 * cPoints [I] Count of endpoints and control points
877 * RETURNS STD
879 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
881 DC * dc = DC_GetDCPtr( hdc );
882 BOOL ret;
884 if(!dc) return FALSE;
886 if(PATH_IsPathOpen(dc->w.path))
887 ret = PATH_PolyBezierTo(hdc, lppt, cPoints);
888 else if(dc->funcs->pPolyBezierTo)
889 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
890 else { /* We'll do it using PolyBezier */
891 POINT *pt;
892 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
893 if(!pt) return FALSE;
894 pt[0].x = dc->w.CursPosX;
895 pt[0].y = dc->w.CursPosY;
896 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
897 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
898 HeapFree( GetProcessHeap(), 0, pt );
900 if(ret) {
901 dc->w.CursPosX = lppt[cPoints-1].x;
902 dc->w.CursPosY = lppt[cPoints-1].y;
904 return ret;
907 /***************************************************************
908 * AngleArc (GDI32.5)
911 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
912 FLOAT eStartAngle, FLOAT eSweepAngle)
914 FIXME("AngleArc, stub\n");
915 return 0;
918 /***************************************************************
919 * PolyDraw (GDI32.270)
922 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
923 DWORD cCount)
925 FIXME("PolyDraw, stub\n");
926 return 0;
929 /******************************************************************
931 * *Very* simple bezier drawing code,
933 * It uses a recursive algorithm to divide the curve in a series
934 * of straight line segements. Not ideal but for me sufficient.
935 * If you are in need for something better look for some incremental
936 * algorithm.
938 * 7 July 1998 Rein Klazes
942 * some macro definitions for bezier drawing
944 * to avoid trucation errors the coordinates are
945 * shifted upwards. When used in drawing they are
946 * shifted down again, including correct rounding
947 * and avoiding floating point arithmatic
948 * 4 bits should allow 27 bits coordinates which I saw
949 * somewere in the win32 doc's
953 #define BEZIERSHIFTBITS 4
954 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
955 #define BEZIERPIXEL BEZIERSHIFTUP(1)
956 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
957 /* maximum depth of recursion */
958 #define BEZIERMAXDEPTH 8
960 /* size of array to store points on */
961 /* enough for one curve */
962 #define BEZIER_INITBUFSIZE (150)
964 /* calculate Bezier average, in this case the middle
965 * correctly rounded...
966 * */
968 #define BEZIERMIDDLE(Mid, P1, P2) \
969 (Mid).x=((P1).x+(P2).x + 1)/2;\
970 (Mid).y=((P1).y+(P2).y + 1)/2;
972 /**********************************************************
973 * BezierCheck helper function to check
974 * that recursion can be terminated
975 * Points[0] and Points[3] are begin and endpoint
976 * Points[1] and Points[2] are control points
977 * level is the recursion depth
978 * returns true if the recusion can be terminated
980 static BOOL BezierCheck( int level, POINT *Points)
982 INT dx, dy;
983 dx=Points[3].x-Points[0].x;
984 dy=Points[3].y-Points[0].y;
985 if(abs(dy)<=abs(dx)){/* shallow line */
986 /* check that control points are between begin and end */
987 if(Points[1].x < Points[0].x){
988 if(Points[1].x < Points[3].x)
989 return FALSE;
990 }else
991 if(Points[1].x > Points[3].x)
992 return FALSE;
993 if(Points[2].x < Points[0].x){
994 if(Points[2].x < Points[3].x)
995 return FALSE;
996 }else
997 if(Points[2].x > Points[3].x)
998 return FALSE;
999 dx=BEZIERSHIFTDOWN(dx);
1000 if(!dx) return TRUE;
1001 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1002 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1003 abs(Points[2].y-Points[0].y-(dy/dx)*
1004 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1005 return FALSE;
1006 else
1007 return TRUE;
1008 }else{ /* steep line */
1009 /* check that control points are between begin and end */
1010 if(Points[1].y < Points[0].y){
1011 if(Points[1].y < Points[3].y)
1012 return FALSE;
1013 }else
1014 if(Points[1].y > Points[3].y)
1015 return FALSE;
1016 if(Points[2].y < Points[0].y){
1017 if(Points[2].y < Points[3].y)
1018 return FALSE;
1019 }else
1020 if(Points[2].y > Points[3].y)
1021 return FALSE;
1022 dy=BEZIERSHIFTDOWN(dy);
1023 if(!dy) return TRUE;
1024 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1025 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1026 abs(Points[2].x-Points[0].x-(dx/dy)*
1027 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1028 return FALSE;
1029 else
1030 return TRUE;
1034 /* Helper for GDI_Bezier.
1035 * Just handles one Bezier, so Points should point to four POINTs
1037 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1038 INT *nPtsOut, INT level )
1040 if(*nPtsOut == *dwOut) {
1041 *dwOut *= 2;
1042 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1043 *dwOut * sizeof(POINT) );
1046 if(!level || BezierCheck(level, Points)) {
1047 if(*nPtsOut == 0) {
1048 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1049 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1050 *nPtsOut = 1;
1052 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1053 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1054 (*nPtsOut) ++;
1055 } else {
1056 POINT Points2[4]; /* for the second recursive call */
1057 Points2[3]=Points[3];
1058 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1059 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1060 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1062 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1063 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1064 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1066 Points2[0]=Points[3];
1068 /* do the two halves */
1069 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1070 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1076 /***********************************************************************
1077 * GDI_Bezier [INTERNAL]
1078 * Calculate line segments that approximate -what microsoft calls- a bezier
1079 * curve.
1080 * The routine recursively divides the curve in two parts until a straight
1081 * line can be drawn
1083 * PARAMS
1085 * Points [I] Ptr to count POINTs which are the end and control points
1086 * of the set of Bezier curves to flatten.
1087 * count [I] Number of Points. Must be 3n+1.
1088 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1089 * lines+1).
1091 * RETURNS
1093 * Ptr to an array of POINTs that contain the lines that approximinate the
1094 * Beziers. The array is allocated on the process heap and it is the caller's
1095 * responsibility to HeapFree it. [this is not a particularly nice interface
1096 * but since we can't know in advance how many points will generate, the
1097 * alternative would be to call the function twice, once to determine the size
1098 * and a second time to do the work - I decided this was too much of a pain].
1100 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1102 POINT *out;
1103 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1105 if((count - 1) % 3 != 0) {
1106 ERR("Invalid no. of points\n");
1107 return NULL;
1109 *nPtsOut = 0;
1110 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1111 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1112 POINT ptBuf[4];
1113 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1114 for(i = 0; i < 4; i++) {
1115 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1116 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1118 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1120 TRACE("Produced %d points\n", *nPtsOut);
1121 return out;