Removed some HEAP_xalloc calls.
[wine.git] / graphics / painting.c
blob3413c58bf39a659952519238dcc85df3ea962ab7
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 "windef.h"
20 #include "wingdi.h"
21 #include "winuser.h"
22 #include "wine/winuser16.h"
24 DEFAULT_DEBUG_CHANNEL(gdi)
27 /***********************************************************************
28 * LineTo16 (GDI.19)
30 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
32 return LineTo( hdc, x, y );
36 /***********************************************************************
37 * LineTo (GDI32.249)
39 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
41 DC * dc = DC_GetDCPtr( hdc );
42 BOOL ret;
44 if(!dc) return FALSE;
46 if(PATH_IsPathOpen(dc->w.path))
47 ret = PATH_LineTo(hdc, x, y);
48 else
49 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc,x,y);
50 if(ret) {
51 dc->w.CursPosX = x;
52 dc->w.CursPosY = y;
54 return ret;
58 /***********************************************************************
59 * MoveTo16 (GDI.20)
61 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
63 POINT16 pt;
65 if (!MoveToEx16(hdc,x,y,&pt))
66 return 0;
67 return MAKELONG(pt.x,pt.y);
71 /***********************************************************************
72 * MoveToEx16 (GDI.483)
74 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
76 POINT pt32;
78 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
79 if (pt) CONV_POINT32TO16( &pt32, pt );
80 return TRUE;
85 /***********************************************************************
86 * MoveToEx (GDI32.254)
88 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
90 DC * dc = DC_GetDCPtr( hdc );
92 if(!dc) return FALSE;
94 if(pt) {
95 pt->x = dc->w.CursPosX;
96 pt->y = dc->w.CursPosY;
98 dc->w.CursPosX = x;
99 dc->w.CursPosY = y;
101 if(PATH_IsPathOpen(dc->w.path))
102 return PATH_MoveTo(hdc);
104 if(dc->funcs->pMoveToEx)
105 return dc->funcs->pMoveToEx(dc,x,y,pt);
106 return FALSE;
110 /***********************************************************************
111 * Arc16 (GDI.23)
113 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
114 INT16 bottom, INT16 xstart, INT16 ystart,
115 INT16 xend, INT16 yend )
117 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
118 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
119 (INT)yend );
123 /***********************************************************************
124 * Arc (GDI32.7)
126 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
127 INT bottom, INT xstart, INT ystart,
128 INT xend, INT yend )
130 DC * dc = DC_GetDCPtr( hdc );
131 if(!dc) return FALSE;
133 if(PATH_IsPathOpen(dc->w.path))
134 return PATH_Arc(hdc, left, top, right, bottom, xstart, ystart, xend,
135 yend);
137 return dc->funcs->pArc &&
138 dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
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_GetDCPtr( hdc );
152 if(!dc) return FALSE;
154 if(dc->funcs->pArcTo)
155 return dc->funcs->pArcTo( dc, left, top, right, bottom,
156 xstart, ystart, xend, yend );
158 * Else emulate it.
159 * According to the documentation, a line is drawn from the current
160 * position to the starting point of the arc.
162 LineTo(hdc, xstart, ystart);
165 * Then the arc is drawn.
167 result = Arc(hdc,
168 left, top,
169 right, bottom,
170 xstart, ystart,
171 xend, yend);
174 * If no error occured, the current position is moved to the ending
175 * point of the arc.
177 if (result)
179 MoveToEx(hdc, xend, yend, NULL);
182 return result;
185 /***********************************************************************
186 * Pie16 (GDI.26)
188 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
189 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
190 INT16 xend, INT16 yend )
192 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
193 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
194 (INT)yend );
198 /***********************************************************************
199 * Pie (GDI32.262)
201 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
202 INT right, INT bottom, INT xstart, INT ystart,
203 INT xend, INT yend )
205 DC * dc = DC_GetDCPtr( hdc );
206 if(!dc) return FALSE;
208 if(PATH_IsPathOpen(dc->w.path)) {
209 FIXME("-> Path: stub\n");
210 return FALSE;
213 return dc->funcs->pPie &&
214 dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
218 /***********************************************************************
219 * Chord16 (GDI.348)
221 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
222 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
223 INT16 xend, INT16 yend )
225 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
229 /***********************************************************************
230 * Chord (GDI32.14)
232 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
233 INT right, INT bottom, INT xstart, INT ystart,
234 INT xend, INT yend )
236 DC * dc = DC_GetDCPtr( hdc );
237 if(!dc) return FALSE;
239 if(PATH_IsPathOpen(dc->w.path)) {
240 FIXME("-> Path: stub\n");
241 return FALSE;
244 return dc->funcs->pChord &&
245 dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
249 /***********************************************************************
250 * Ellipse16 (GDI.24)
252 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
253 INT16 right, INT16 bottom )
255 return Ellipse( hdc, left, top, right, bottom );
259 /***********************************************************************
260 * Ellipse (GDI32.75)
262 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
263 INT right, INT bottom )
265 DC * dc = DC_GetDCPtr( hdc );
266 if(!dc) return FALSE;
268 if(PATH_IsPathOpen(dc->w.path)) {
269 FIXME("-> Path: stub\n");
270 return FALSE;
273 return dc->funcs->pEllipse &&
274 dc->funcs->pEllipse(dc,left,top,right,bottom);
278 /***********************************************************************
279 * Rectangle16 (GDI.27)
281 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
282 INT16 right, INT16 bottom )
284 return Rectangle( hdc, left, top, right, bottom );
288 /***********************************************************************
289 * Rectangle (GDI32.283)
291 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
292 INT right, INT bottom )
294 DC * dc = DC_GetDCPtr( hdc );
295 if(!dc) return FALSE;
297 if(PATH_IsPathOpen(dc->w.path))
298 return PATH_Rectangle(hdc, left, top, right, bottom);
300 return dc->funcs->pRectangle &&
301 dc->funcs->pRectangle(dc,left,top,right,bottom);
305 /***********************************************************************
306 * RoundRect16 (GDI.28)
308 BOOL16 WINAPI RoundRect16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
309 INT16 bottom, INT16 ell_width, INT16 ell_height )
311 return RoundRect( hdc, left, top, right, bottom, ell_width, ell_height );
315 /***********************************************************************
316 * RoundRect (GDI32.291)
318 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
319 INT bottom, INT ell_width, INT ell_height )
321 DC * dc = DC_GetDCPtr( hdc );
322 if(!dc) return FALSE;
324 if(PATH_IsPathOpen(dc->w.path)) {
325 FIXME("-> Path: stub\n");
326 return FALSE;
329 return dc->funcs->pRoundRect &&
330 dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
333 /***********************************************************************
334 * SetPixel16 (GDI.31)
336 COLORREF WINAPI SetPixel16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
338 return SetPixel( hdc, x, y, color );
342 /***********************************************************************
343 * SetPixel (GDI32.327)
345 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
347 DC * dc = DC_GetDCPtr( hdc );
349 if (!dc || !dc->funcs->pSetPixel) return 0;
350 return dc->funcs->pSetPixel(dc,x,y,color);
353 /***********************************************************************
354 * SetPixelV (GDI32.329)
356 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
358 DC * dc = DC_GetDCPtr( hdc );
360 if (!dc || !dc->funcs->pSetPixel) return FALSE;
361 dc->funcs->pSetPixel(dc,x,y,color);
362 return TRUE;
365 /***********************************************************************
366 * GetPixel16 (GDI.83)
368 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
370 return GetPixel( hdc, x, y );
374 /***********************************************************************
375 * GetPixel (GDI32.211)
377 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
379 DC * dc = DC_GetDCPtr( hdc );
381 if (!dc) return 0;
382 #ifdef SOLITAIRE_SPEED_HACK
383 return 0;
384 #endif
386 /* FIXME: should this be in the graphics driver? */
387 if (!PtVisible( hdc, x, y )) return 0;
388 if (!dc || !dc->funcs->pGetPixel) return 0;
389 return dc->funcs->pGetPixel(dc,x,y);
393 /******************************************************************************
394 * ChoosePixelFormat [GDI32.13]
395 * Matches a pixel format to given format
397 * PARAMS
398 * hdc [I] Device context to search for best pixel match
399 * ppfd [I] Pixel format for which a match is sought
401 * RETURNS
402 * Success: Pixel format index closest to given format
403 * Failure: 0
405 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
407 FIXME("(%d,%p): stub\n",hdc,ppfd);
408 return 1;
412 /******************************************************************************
413 * SetPixelFormat [GDI32.328]
414 * Sets pixel format of device context
416 * PARAMS
417 * hdc [I] Device context to search for best pixel match
418 * iPixelFormat [I] Pixel format index
419 * ppfd [I] Pixel format for which a match is sought
421 * RETURNS STD
423 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
424 const PIXELFORMATDESCRIPTOR *ppfd)
426 FIXME("(%d,%d,%p): stub\n",hdc,iPixelFormat,ppfd);
427 return TRUE;
431 /******************************************************************************
432 * GetPixelFormat [GDI32.212]
433 * Gets index of pixel format of DC
435 * PARAMETERS
436 * hdc [I] Device context whose pixel format index is sought
438 * RETURNS
439 * Success: Currently selected pixel format
440 * Failure: 0
442 INT WINAPI GetPixelFormat( HDC hdc )
444 FIXME("(%d): stub\n",hdc);
445 return 1;
449 /******************************************************************************
450 * DescribePixelFormat [GDI32.71]
451 * Gets info about pixel format from DC
453 * PARAMS
454 * hdc [I] Device context
455 * iPixelFormat [I] Pixel format selector
456 * nBytes [I] Size of buffer
457 * ppfd [O] Pointer to structure to receive pixel format data
459 * RETURNS
460 * Success: Maximum pixel format index of the device context
461 * Failure: 0
463 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
464 LPPIXELFORMATDESCRIPTOR ppfd )
466 FIXME("(%d,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
467 ppfd->nSize = nBytes;
468 ppfd->nVersion = 1;
469 return 3;
473 /******************************************************************************
474 * SwapBuffers [GDI32.354]
475 * Exchanges front and back buffers of window
477 * PARAMS
478 * hdc [I] Device context whose buffers get swapped
480 * RETURNS STD
482 BOOL WINAPI SwapBuffers( HDC hdc )
484 FIXME("(%d): stub\n",hdc);
485 return TRUE;
489 /***********************************************************************
490 * PaintRgn16 (GDI.43)
492 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
494 return PaintRgn( hdc, hrgn );
498 /***********************************************************************
499 * PaintRgn (GDI32.259)
501 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
503 DC * dc = DC_GetDCPtr( hdc );
505 return dc && dc->funcs->pPaintRgn &&
506 dc->funcs->pPaintRgn(dc,hrgn);
510 /***********************************************************************
511 * FillRgn16 (GDI.40)
513 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
515 return FillRgn( hdc, hrgn, hbrush );
519 /***********************************************************************
520 * FillRgn (GDI32.101)
522 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
524 BOOL retval;
525 HBRUSH prevBrush;
526 DC * dc = DC_GetDCPtr( hdc );
528 if (!dc) return FALSE;
529 if(dc->funcs->pFillRgn)
530 return dc->funcs->pFillRgn(dc, hrgn, hbrush);
532 prevBrush = SelectObject( hdc, hbrush );
533 if (!prevBrush) return FALSE;
534 retval = PaintRgn( hdc, hrgn );
535 SelectObject( hdc, prevBrush );
536 return retval;
540 /***********************************************************************
541 * FrameRgn16 (GDI.41)
543 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
544 INT16 nWidth, INT16 nHeight )
546 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
550 /***********************************************************************
551 * FrameRgn (GDI32.105)
553 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
554 INT nWidth, INT nHeight )
556 HRGN tmp;
557 DC *dc = DC_GetDCPtr( hdc );
559 if(dc->funcs->pFrameRgn)
560 return dc->funcs->pFrameRgn( dc, hrgn, hbrush, nWidth, nHeight );
562 tmp = CreateRectRgn( 0, 0, 0, 0 );
563 if(!REGION_FrameRgn( tmp, hrgn, nWidth, nHeight )) return FALSE;
564 FillRgn( hdc, tmp, hbrush );
565 DeleteObject( tmp );
566 return TRUE;
570 /***********************************************************************
571 * InvertRgn16 (GDI.42)
573 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
575 return InvertRgn( hdc, hrgn );
579 /***********************************************************************
580 * InvertRgn (GDI32.246)
582 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
584 HBRUSH prevBrush;
585 INT prevROP;
586 BOOL retval;
587 DC *dc = DC_GetDCPtr( hdc );
589 if(dc->funcs->pInvertRgn)
590 return dc->funcs->pInvertRgn( dc, hrgn );
592 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
593 prevROP = SetROP2( hdc, R2_NOT );
594 retval = PaintRgn( hdc, hrgn );
595 SelectObject( hdc, prevBrush );
596 SetROP2( hdc, prevROP );
597 return retval;
600 /**********************************************************************
601 * Polyline16 (GDI.37)
603 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
605 register int i;
606 BOOL16 ret;
607 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
608 count*sizeof(POINT) );
610 if (!pt32) return FALSE;
611 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
612 ret = Polyline(hdc,pt32,count);
613 HeapFree( GetProcessHeap(), 0, pt32 );
614 return ret;
618 /**********************************************************************
619 * Polyline (GDI32.276)
621 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
623 DC * dc = DC_GetDCPtr( hdc );
624 if(!dc) return FALSE;
626 if(PATH_IsPathOpen(dc->w.path))
627 return PATH_Polyline(hdc, pt, count);
629 return dc->funcs->pPolyline &&
630 dc->funcs->pPolyline(dc,pt,count);
633 /**********************************************************************
634 * PolylineTo (GDI32.277)
636 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
638 DC * dc = DC_GetDCPtr( hdc );
639 BOOL ret;
641 if(!dc) return FALSE;
643 if(PATH_IsPathOpen(dc->w.path))
644 ret = PATH_PolylineTo(hdc, pt, cCount);
646 else if(dc->funcs->pPolylineTo)
647 ret = dc->funcs->pPolylineTo(dc, pt, cCount);
649 else { /* do it using Polyline */
650 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
651 sizeof(POINT) * (cCount + 1) );
652 if(!pts) return FALSE;
654 pts[0].x = dc->w.CursPosX;
655 pts[0].y = dc->w.CursPosY;
656 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
657 ret = Polyline( hdc, pts, cCount + 1 );
658 HeapFree( GetProcessHeap(), 0, pts );
660 if(ret) {
661 dc->w.CursPosX = pt[cCount-1].x;
662 dc->w.CursPosY = pt[cCount-1].y;
664 return ret;
667 /**********************************************************************
668 * Polygon16 (GDI.36)
670 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
672 register int i;
673 BOOL ret;
674 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
675 count*sizeof(POINT) );
677 if (!pt32) return FALSE;
678 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
679 ret = Polygon(hdc,pt32,count);
680 HeapFree( GetProcessHeap(), 0, pt32 );
681 return ret;
685 /**********************************************************************
686 * Polygon (GDI32.275)
688 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
690 DC * dc = DC_GetDCPtr( hdc );
691 if(!dc) return FALSE;
693 if(PATH_IsPathOpen(dc->w.path))
694 return PATH_Polygon(hdc, pt, count);
696 return dc->funcs->pPolygon &&
697 dc->funcs->pPolygon(dc,pt,count);
701 /**********************************************************************
702 * PolyPolygon16 (GDI.450)
704 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
705 UINT16 polygons )
707 int i,nrpts;
708 LPPOINT pt32;
709 LPINT counts32;
710 BOOL16 ret;
712 nrpts=0;
713 for (i=polygons;i--;)
714 nrpts+=counts[i];
715 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
716 if(pt32 == NULL) return FALSE;
717 for (i=nrpts;i--;)
718 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
719 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
720 if(counts32 == NULL) {
721 HeapFree( GetProcessHeap(), 0, pt32 );
722 return FALSE;
724 for (i=polygons;i--;) counts32[i]=counts[i];
726 ret = PolyPolygon(hdc,pt32,counts32,polygons);
727 HeapFree( GetProcessHeap(), 0, counts32 );
728 HeapFree( GetProcessHeap(), 0, pt32 );
729 return ret;
732 /**********************************************************************
733 * PolyPolygon (GDI.450)
735 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
736 UINT polygons )
738 DC * dc = DC_GetDCPtr( hdc );
739 if(!dc) return FALSE;
741 if(PATH_IsPathOpen(dc->w.path))
742 return PATH_PolyPolygon(hdc, pt, counts, polygons);
744 return dc->funcs->pPolyPolygon &&
745 dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
748 /**********************************************************************
749 * PolyPolyline (GDI32.272)
751 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
752 DWORD polylines )
754 DC * dc = DC_GetDCPtr( hdc );
755 if(!dc) return FALSE;
757 if(PATH_IsPathOpen(dc->w.path))
758 return PATH_PolyPolyline(hdc, pt, counts, polylines);
760 return dc->funcs->pPolyPolyline &&
761 dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
764 /**********************************************************************
765 * ExtFloodFill16 (GDI.372)
767 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
768 UINT16 fillType )
770 return ExtFloodFill( hdc, x, y, color, fillType );
774 /**********************************************************************
775 * ExtFloodFill (GDI32.96)
777 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
778 UINT fillType )
780 DC *dc = DC_GetDCPtr( hdc );
782 return dc && dc->funcs->pExtFloodFill &&
783 dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
787 /**********************************************************************
788 * FloodFill16 (GDI.25)
790 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
792 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
796 /**********************************************************************
797 * FloodFill (GDI32.104)
799 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
801 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
805 /******************************************************************************
806 * PolyBezier16 [GDI.502]
808 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
810 int i;
811 BOOL16 ret;
812 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
813 cPoints*sizeof(POINT) );
814 if(!pt32) return FALSE;
815 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
816 ret= PolyBezier(hDc, pt32, cPoints);
817 HeapFree( GetProcessHeap(), 0, pt32 );
818 return ret;
821 /******************************************************************************
822 * PolyBezierTo16 [GDI.503]
824 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
826 int i;
827 BOOL16 ret;
828 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
829 cPoints*sizeof(POINT) );
830 if(!pt32) return FALSE;
831 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
832 ret= PolyBezierTo(hDc, pt32, cPoints);
833 HeapFree( GetProcessHeap(), 0, pt32 );
834 return ret;
837 /******************************************************************************
838 * PolyBezier [GDI32.268]
839 * Draws one or more Bezier curves
841 * PARAMS
842 * hDc [I] Handle to device context
843 * lppt [I] Pointer to endpoints and control points
844 * cPoints [I] Count of endpoints and control points
846 * RETURNS STD
848 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
850 DC * dc = DC_GetDCPtr( hdc );
851 if(!dc) return FALSE;
853 if(PATH_IsPathOpen(dc->w.path))
854 return PATH_PolyBezier(hdc, lppt, cPoints);
856 if(dc->funcs->pPolyBezier)
857 return dc->funcs->pPolyBezier(dc, lppt, cPoints);
859 /* We'll convert it into line segments and draw them using Polyline */
861 POINT *Pts;
862 INT nOut;
863 BOOL ret;
865 Pts = GDI_Bezier( lppt, cPoints, &nOut );
866 if(!Pts) return FALSE;
867 TRACE("Pts = %p, no = %d\n", Pts, nOut);
868 ret = Polyline( dc->hSelf, Pts, nOut );
869 HeapFree( GetProcessHeap(), 0, Pts );
870 return ret;
874 /******************************************************************************
875 * PolyBezierTo [GDI32.269]
876 * Draws one or more Bezier curves
878 * PARAMS
879 * hDc [I] Handle to device context
880 * lppt [I] Pointer to endpoints and control points
881 * cPoints [I] Count of endpoints and control points
883 * RETURNS STD
885 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
887 DC * dc = DC_GetDCPtr( hdc );
888 BOOL ret;
890 if(!dc) return FALSE;
892 if(PATH_IsPathOpen(dc->w.path))
893 ret = PATH_PolyBezierTo(hdc, lppt, cPoints);
894 else if(dc->funcs->pPolyBezierTo)
895 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
896 else { /* We'll do it using PolyBezier */
897 POINT *pt;
898 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
899 if(!pt) return FALSE;
900 pt[0].x = dc->w.CursPosX;
901 pt[0].y = dc->w.CursPosY;
902 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
903 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
904 HeapFree( GetProcessHeap(), 0, pt );
906 if(ret) {
907 dc->w.CursPosX = lppt[cPoints-1].x;
908 dc->w.CursPosY = lppt[cPoints-1].y;
910 return ret;
913 /***********************************************************************
914 * AngleArc (GDI32.5)
917 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
918 FLOAT eStartAngle, FLOAT eSweepAngle)
920 FIXME("AngleArc, stub\n");
921 return 0;
924 /***********************************************************************
925 * PolyDraw (GDI32.270)
928 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
929 DWORD cCount)
931 FIXME("PolyDraw, stub\n");
932 return 0;
935 /******************************************************************
937 * *Very* simple bezier drawing code,
939 * It uses a recursive algorithm to divide the curve in a series
940 * of straight line segements. Not ideal but for me sufficient.
941 * If you are in need for something better look for some incremental
942 * algorithm.
944 * 7 July 1998 Rein Klazes
948 * some macro definitions for bezier drawing
950 * to avoid trucation errors the coordinates are
951 * shifted upwards. When used in drawing they are
952 * shifted down again, including correct rounding
953 * and avoiding floating point arithmatic
954 * 4 bits should allow 27 bits coordinates which I saw
955 * somewere in the win32 doc's
959 #define BEZIERSHIFTBITS 4
960 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
961 #define BEZIERPIXEL BEZIERSHIFTUP(1)
962 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
963 /* maximum depth of recursion */
964 #define BEZIERMAXDEPTH 8
966 /* size of array to store points on */
967 /* enough for one curve */
968 #define BEZIER_INITBUFSIZE (150)
970 /* calculate Bezier average, in this case the middle
971 * correctly rounded...
972 * */
974 #define BEZIERMIDDLE(Mid, P1, P2) \
975 (Mid).x=((P1).x+(P2).x + 1)/2;\
976 (Mid).y=((P1).y+(P2).y + 1)/2;
978 /**********************************************************
979 * BezierCheck helper function to check
980 * that recursion can be terminated
981 * Points[0] and Points[3] are begin and endpoint
982 * Points[1] and Points[2] are control points
983 * level is the recursion depth
984 * returns true if the recusion can be terminated
986 static BOOL BezierCheck( int level, POINT *Points)
988 INT dx, dy;
989 dx=Points[3].x-Points[0].x;
990 dy=Points[3].y-Points[0].y;
991 if(abs(dy)<=abs(dx)){/* shallow line */
992 /* check that control points are between begin and end */
993 if(Points[1].x < Points[0].x){
994 if(Points[1].x < Points[3].x)
995 return FALSE;
996 }else
997 if(Points[1].x > Points[3].x)
998 return FALSE;
999 if(Points[2].x < Points[0].x){
1000 if(Points[2].x < Points[3].x)
1001 return FALSE;
1002 }else
1003 if(Points[2].x > Points[3].x)
1004 return FALSE;
1005 dx=BEZIERSHIFTDOWN(dx);
1006 if(!dx) return TRUE;
1007 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1008 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1009 abs(Points[2].y-Points[0].y-(dy/dx)*
1010 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1011 return FALSE;
1012 else
1013 return TRUE;
1014 }else{ /* steep line */
1015 /* check that control points are between begin and end */
1016 if(Points[1].y < Points[0].y){
1017 if(Points[1].y < Points[3].y)
1018 return FALSE;
1019 }else
1020 if(Points[1].y > Points[3].y)
1021 return FALSE;
1022 if(Points[2].y < Points[0].y){
1023 if(Points[2].y < Points[3].y)
1024 return FALSE;
1025 }else
1026 if(Points[2].y > Points[3].y)
1027 return FALSE;
1028 dy=BEZIERSHIFTDOWN(dy);
1029 if(!dy) return TRUE;
1030 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1031 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1032 abs(Points[2].x-Points[0].x-(dx/dy)*
1033 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1034 return FALSE;
1035 else
1036 return TRUE;
1040 /* Helper for GDI_Bezier.
1041 * Just handles one Bezier, so Points should point to four POINTs
1043 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1044 INT *nPtsOut, INT level )
1046 if(*nPtsOut == *dwOut) {
1047 *dwOut *= 2;
1048 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1049 *dwOut * sizeof(POINT) );
1052 if(!level || BezierCheck(level, Points)) {
1053 if(*nPtsOut == 0) {
1054 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1055 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1056 *nPtsOut = 1;
1058 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1059 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1060 (*nPtsOut) ++;
1061 } else {
1062 POINT Points2[4]; /* for the second recursive call */
1063 Points2[3]=Points[3];
1064 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1065 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1066 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1068 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1069 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1070 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1072 Points2[0]=Points[3];
1074 /* do the two halves */
1075 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1076 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1082 /***********************************************************************
1083 * GDI_Bezier [INTERNAL]
1084 * Calculate line segments that approximate -what microsoft calls- a bezier
1085 * curve.
1086 * The routine recursively divides the curve in two parts until a straight
1087 * line can be drawn
1089 * PARAMS
1091 * Points [I] Ptr to count POINTs which are the end and control points
1092 * of the set of Bezier curves to flatten.
1093 * count [I] Number of Points. Must be 3n+1.
1094 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1095 * lines+1).
1097 * RETURNS
1099 * Ptr to an array of POINTs that contain the lines that approximinate the
1100 * Beziers. The array is allocated on the process heap and it is the caller's
1101 * responsibility to HeapFree it. [this is not a particularly nice interface
1102 * but since we can't know in advance how many points will generate, the
1103 * alternative would be to call the function twice, once to determine the size
1104 * and a second time to do the work - I decided this was too much of a pain].
1106 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1108 POINT *out;
1109 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1111 if((count - 1) % 3 != 0) {
1112 ERR("Invalid no. of points\n");
1113 return NULL;
1115 *nPtsOut = 0;
1116 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1117 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1118 POINT ptBuf[4];
1119 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1120 for(i = 0; i < 4; i++) {
1121 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1122 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1124 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1126 TRACE("Produced %d points\n", *nPtsOut);
1127 return out;