Do not erase local files on uninstall if install dir does not exist.
[wine.git] / graphics / painting.c
blob7f3d3710ceb37db666b58655e69bf3d95871ad3f
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)HEAP_xalloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
716 for (i=nrpts;i--;)
717 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
718 counts32 = (LPINT)HEAP_xalloc( GetProcessHeap(), 0,
719 polygons*sizeof(INT) );
720 for (i=polygons;i--;) counts32[i]=counts[i];
722 ret = PolyPolygon(hdc,pt32,counts32,polygons);
723 HeapFree( GetProcessHeap(), 0, counts32 );
724 HeapFree( GetProcessHeap(), 0, pt32 );
725 return ret;
728 /**********************************************************************
729 * PolyPolygon (GDI.450)
731 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
732 UINT polygons )
734 DC * dc = DC_GetDCPtr( hdc );
735 if(!dc) return FALSE;
737 if(PATH_IsPathOpen(dc->w.path))
738 return PATH_PolyPolygon(hdc, pt, counts, polygons);
740 return dc->funcs->pPolyPolygon &&
741 dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
744 /**********************************************************************
745 * PolyPolyline (GDI32.272)
747 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
748 DWORD polylines )
750 DC * dc = DC_GetDCPtr( hdc );
751 if(!dc) return FALSE;
753 if(PATH_IsPathOpen(dc->w.path))
754 return PATH_PolyPolyline(hdc, pt, counts, polylines);
756 return dc->funcs->pPolyPolyline &&
757 dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
760 /**********************************************************************
761 * ExtFloodFill16 (GDI.372)
763 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
764 UINT16 fillType )
766 return ExtFloodFill( hdc, x, y, color, fillType );
770 /**********************************************************************
771 * ExtFloodFill (GDI32.96)
773 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
774 UINT fillType )
776 DC *dc = DC_GetDCPtr( hdc );
778 return dc && dc->funcs->pExtFloodFill &&
779 dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
783 /**********************************************************************
784 * FloodFill16 (GDI.25)
786 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
788 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
792 /**********************************************************************
793 * FloodFill (GDI32.104)
795 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
797 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
801 /******************************************************************************
802 * PolyBezier16 [GDI.502]
804 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
806 int i;
807 BOOL16 ret;
808 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
809 cPoints*sizeof(POINT) );
810 if(!pt32) return FALSE;
811 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
812 ret= PolyBezier(hDc, pt32, cPoints);
813 HeapFree( GetProcessHeap(), 0, pt32 );
814 return ret;
817 /******************************************************************************
818 * PolyBezierTo16 [GDI.503]
820 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
822 int i;
823 BOOL16 ret;
824 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
825 cPoints*sizeof(POINT) );
826 if(!pt32) return FALSE;
827 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
828 ret= PolyBezierTo(hDc, pt32, cPoints);
829 HeapFree( GetProcessHeap(), 0, pt32 );
830 return ret;
833 /******************************************************************************
834 * PolyBezier [GDI32.268]
835 * Draws one or more Bezier curves
837 * PARAMS
838 * hDc [I] Handle to device context
839 * lppt [I] Pointer to endpoints and control points
840 * cPoints [I] Count of endpoints and control points
842 * RETURNS STD
844 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
846 DC * dc = DC_GetDCPtr( hdc );
847 if(!dc) return FALSE;
849 if(PATH_IsPathOpen(dc->w.path))
850 return PATH_PolyBezier(hdc, lppt, cPoints);
852 if(dc->funcs->pPolyBezier)
853 return dc->funcs->pPolyBezier(dc, lppt, cPoints);
855 /* We'll convert it into line segments and draw them using Polyline */
857 POINT *Pts;
858 INT nOut;
859 BOOL ret;
861 Pts = GDI_Bezier( lppt, cPoints, &nOut );
862 if(!Pts) return FALSE;
863 TRACE("Pts = %p, no = %d\n", Pts, nOut);
864 ret = Polyline( dc->hSelf, Pts, nOut );
865 HeapFree( GetProcessHeap(), 0, Pts );
866 return ret;
870 /******************************************************************************
871 * PolyBezierTo [GDI32.269]
872 * Draws one or more Bezier curves
874 * PARAMS
875 * hDc [I] Handle to device context
876 * lppt [I] Pointer to endpoints and control points
877 * cPoints [I] Count of endpoints and control points
879 * RETURNS STD
881 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
883 DC * dc = DC_GetDCPtr( hdc );
884 BOOL ret;
886 if(!dc) return FALSE;
888 if(PATH_IsPathOpen(dc->w.path))
889 ret = PATH_PolyBezierTo(hdc, lppt, cPoints);
890 else if(dc->funcs->pPolyBezierTo)
891 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
892 else { /* We'll do it using PolyBezier */
893 POINT *pt;
894 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
895 if(!pt) return FALSE;
896 pt[0].x = dc->w.CursPosX;
897 pt[0].y = dc->w.CursPosY;
898 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
899 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
900 HeapFree( GetProcessHeap(), 0, pt );
902 if(ret) {
903 dc->w.CursPosX = lppt[cPoints-1].x;
904 dc->w.CursPosY = lppt[cPoints-1].y;
906 return ret;
909 /***************************************************************
910 * AngleArc (GDI32.5)
913 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius,
914 FLOAT eStartAngle, FLOAT eSweepAngle)
916 FIXME("AngleArc, stub\n");
917 return 0;
920 /***************************************************************
921 * PolyDraw (GDI32.270)
924 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
925 DWORD cCount)
927 FIXME("PolyDraw, stub\n");
928 return 0;
931 /******************************************************************
933 * *Very* simple bezier drawing code,
935 * It uses a recursive algorithm to divide the curve in a series
936 * of straight line segements. Not ideal but for me sufficient.
937 * If you are in need for something better look for some incremental
938 * algorithm.
940 * 7 July 1998 Rein Klazes
944 * some macro definitions for bezier drawing
946 * to avoid trucation errors the coordinates are
947 * shifted upwards. When used in drawing they are
948 * shifted down again, including correct rounding
949 * and avoiding floating point arithmatic
950 * 4 bits should allow 27 bits coordinates which I saw
951 * somewere in the win32 doc's
955 #define BEZIERSHIFTBITS 4
956 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
957 #define BEZIERPIXEL BEZIERSHIFTUP(1)
958 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
959 /* maximum depth of recursion */
960 #define BEZIERMAXDEPTH 8
962 /* size of array to store points on */
963 /* enough for one curve */
964 #define BEZIER_INITBUFSIZE (150)
966 /* calculate Bezier average, in this case the middle
967 * correctly rounded...
968 * */
970 #define BEZIERMIDDLE(Mid, P1, P2) \
971 (Mid).x=((P1).x+(P2).x + 1)/2;\
972 (Mid).y=((P1).y+(P2).y + 1)/2;
974 /**********************************************************
975 * BezierCheck helper function to check
976 * that recursion can be terminated
977 * Points[0] and Points[3] are begin and endpoint
978 * Points[1] and Points[2] are control points
979 * level is the recursion depth
980 * returns true if the recusion can be terminated
982 static BOOL BezierCheck( int level, POINT *Points)
984 INT dx, dy;
985 dx=Points[3].x-Points[0].x;
986 dy=Points[3].y-Points[0].y;
987 if(abs(dy)<=abs(dx)){/* shallow line */
988 /* check that control points are between begin and end */
989 if(Points[1].x < Points[0].x){
990 if(Points[1].x < Points[3].x)
991 return FALSE;
992 }else
993 if(Points[1].x > Points[3].x)
994 return FALSE;
995 if(Points[2].x < Points[0].x){
996 if(Points[2].x < Points[3].x)
997 return FALSE;
998 }else
999 if(Points[2].x > Points[3].x)
1000 return FALSE;
1001 dx=BEZIERSHIFTDOWN(dx);
1002 if(!dx) return TRUE;
1003 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1004 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1005 abs(Points[2].y-Points[0].y-(dy/dx)*
1006 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1007 return FALSE;
1008 else
1009 return TRUE;
1010 }else{ /* steep line */
1011 /* check that control points are between begin and end */
1012 if(Points[1].y < Points[0].y){
1013 if(Points[1].y < Points[3].y)
1014 return FALSE;
1015 }else
1016 if(Points[1].y > Points[3].y)
1017 return FALSE;
1018 if(Points[2].y < Points[0].y){
1019 if(Points[2].y < Points[3].y)
1020 return FALSE;
1021 }else
1022 if(Points[2].y > Points[3].y)
1023 return FALSE;
1024 dy=BEZIERSHIFTDOWN(dy);
1025 if(!dy) return TRUE;
1026 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1027 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1028 abs(Points[2].x-Points[0].x-(dx/dy)*
1029 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1030 return FALSE;
1031 else
1032 return TRUE;
1036 /* Helper for GDI_Bezier.
1037 * Just handles one Bezier, so Points should point to four POINTs
1039 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1040 INT *nPtsOut, INT level )
1042 if(*nPtsOut == *dwOut) {
1043 *dwOut *= 2;
1044 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1045 *dwOut * sizeof(POINT) );
1048 if(!level || BezierCheck(level, Points)) {
1049 if(*nPtsOut == 0) {
1050 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1051 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1052 *nPtsOut = 1;
1054 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1055 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1056 (*nPtsOut) ++;
1057 } else {
1058 POINT Points2[4]; /* for the second recursive call */
1059 Points2[3]=Points[3];
1060 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1061 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1062 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1064 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1065 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1066 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1068 Points2[0]=Points[3];
1070 /* do the two halves */
1071 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1072 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1078 /***********************************************************************
1079 * GDI_Bezier [INTERNAL]
1080 * Calculate line segments that approximate -what microsoft calls- a bezier
1081 * curve.
1082 * The routine recursively divides the curve in two parts until a straight
1083 * line can be drawn
1085 * PARAMS
1087 * Points [I] Ptr to count POINTs which are the end and control points
1088 * of the set of Bezier curves to flatten.
1089 * count [I] Number of Points. Must be 3n+1.
1090 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1091 * lines+1).
1093 * RETURNS
1095 * Ptr to an array of POINTs that contain the lines that approximinate the
1096 * Beziers. The array is allocated on the process heap and it is the caller's
1097 * responsibility to HeapFree it. [this is not a particularly nice interface
1098 * but since we can't know in advance how many points will generate, the
1099 * alternative would be to call the function twice, once to determine the size
1100 * and a second time to do the work - I decided this was too much of a pain].
1102 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1104 POINT *out;
1105 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1107 if((count - 1) % 3 != 0) {
1108 ERR("Invalid no. of points\n");
1109 return NULL;
1111 *nPtsOut = 0;
1112 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1113 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1114 POINT ptBuf[4];
1115 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1116 for(i = 0; i < 4; i++) {
1117 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1118 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1120 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1122 TRACE("Produced %d points\n", *nPtsOut);
1123 return out;