Correct Word breaking in centred/right justified mode; it was leaving a
[wine/dcerpc.git] / graphics / painting.c
blobe6d1b4cfde9e7ddd1999ec88c54de16e8c38ee4e
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 "region.h"
18 #include "path.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(gdi);
24 /***********************************************************************
25 * LineTo (GDI.19)
27 BOOL16 WINAPI LineTo16( HDC16 hdc, INT16 x, INT16 y )
29 return LineTo( hdc, x, y );
33 /***********************************************************************
34 * LineTo (GDI32.@)
36 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
38 DC * dc = DC_GetDCUpdate( hdc );
39 BOOL ret;
41 if(!dc) return FALSE;
43 if(PATH_IsPathOpen(dc->path))
44 ret = PATH_LineTo(dc, x, y);
45 else
46 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc,x,y);
47 if(ret) {
48 dc->CursPosX = x;
49 dc->CursPosY = y;
51 GDI_ReleaseObj( hdc );
52 return ret;
56 /***********************************************************************
57 * MoveTo (GDI.20)
59 DWORD WINAPI MoveTo16( HDC16 hdc, INT16 x, INT16 y )
61 POINT pt;
63 if (!MoveToEx( (HDC)hdc, x, y, &pt )) return 0;
64 return MAKELONG(pt.x,pt.y);
68 /***********************************************************************
69 * MoveToEx (GDI.483)
71 BOOL16 WINAPI MoveToEx16( HDC16 hdc, INT16 x, INT16 y, LPPOINT16 pt )
73 POINT pt32;
75 if (!MoveToEx( (HDC)hdc, (INT)x, (INT)y, &pt32 )) return FALSE;
76 if (pt) CONV_POINT32TO16( &pt32, pt );
77 return TRUE;
81 /***********************************************************************
82 * MoveToEx (GDI32.@)
84 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
86 BOOL ret = TRUE;
87 DC * dc = DC_GetDCPtr( hdc );
89 if(!dc) return FALSE;
91 if(pt) {
92 pt->x = dc->CursPosX;
93 pt->y = dc->CursPosY;
95 dc->CursPosX = x;
96 dc->CursPosY = y;
98 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
99 else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc,x,y);
100 GDI_ReleaseObj( hdc );
101 return ret;
105 /***********************************************************************
106 * Arc (GDI.23)
108 BOOL16 WINAPI Arc16( HDC16 hdc, INT16 left, INT16 top, INT16 right,
109 INT16 bottom, INT16 xstart, INT16 ystart,
110 INT16 xend, INT16 yend )
112 return Arc( (HDC)hdc, (INT)left, (INT)top, (INT)right,
113 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
114 (INT)yend );
118 /***********************************************************************
119 * Arc (GDI32.@)
121 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
122 INT bottom, INT xstart, INT ystart,
123 INT xend, INT yend )
125 BOOL ret = FALSE;
126 DC * dc = DC_GetDCUpdate( hdc );
127 if (dc)
129 if(PATH_IsPathOpen(dc->path))
130 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
131 else if (dc->funcs->pArc)
132 ret = dc->funcs->pArc(dc,left,top,right,bottom,xstart,ystart,xend,yend);
133 GDI_ReleaseObj( hdc );
135 return ret;
138 /***********************************************************************
139 * ArcTo (GDI32.@)
141 BOOL WINAPI ArcTo( HDC hdc,
142 INT left, INT top,
143 INT right, INT bottom,
144 INT xstart, INT ystart,
145 INT xend, INT yend )
147 BOOL result;
148 DC * dc = DC_GetDCUpdate( hdc );
149 if(!dc) return FALSE;
151 if(dc->funcs->pArcTo)
153 result = dc->funcs->pArcTo( dc, left, top, right, bottom,
154 xstart, ystart, xend, yend );
155 GDI_ReleaseObj( hdc );
156 return result;
158 GDI_ReleaseObj( hdc );
160 * Else emulate it.
161 * According to the documentation, a line is drawn from the current
162 * position to the starting point of the arc.
164 LineTo(hdc, xstart, ystart);
166 * Then the arc is drawn.
168 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
170 * If no error occured, the current position is moved to the ending
171 * point of the arc.
173 if (result) MoveToEx(hdc, xend, yend, NULL);
174 return result;
177 /***********************************************************************
178 * Pie (GDI.26)
180 BOOL16 WINAPI Pie16( HDC16 hdc, INT16 left, INT16 top,
181 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
182 INT16 xend, INT16 yend )
184 return Pie( (HDC)hdc, (INT)left, (INT)top, (INT)right,
185 (INT)bottom, (INT)xstart, (INT)ystart, (INT)xend,
186 (INT)yend );
190 /***********************************************************************
191 * Pie (GDI32.@)
193 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
194 INT right, INT bottom, INT xstart, INT ystart,
195 INT xend, INT yend )
197 BOOL ret = FALSE;
198 DC * dc = DC_GetDCUpdate( hdc );
199 if (!dc) return FALSE;
201 if(PATH_IsPathOpen(dc->path))
202 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
203 else if(dc->funcs->pPie)
204 ret = dc->funcs->pPie(dc,left,top,right,bottom,xstart,ystart,xend,yend);
206 GDI_ReleaseObj( hdc );
207 return ret;
211 /***********************************************************************
212 * Chord (GDI.348)
214 BOOL16 WINAPI Chord16( HDC16 hdc, INT16 left, INT16 top,
215 INT16 right, INT16 bottom, INT16 xstart, INT16 ystart,
216 INT16 xend, INT16 yend )
218 return Chord( hdc, left, top, right, bottom, xstart, ystart, xend, yend );
222 /***********************************************************************
223 * Chord (GDI32.@)
225 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
226 INT right, INT bottom, INT xstart, INT ystart,
227 INT xend, INT yend )
229 BOOL ret = FALSE;
230 DC * dc = DC_GetDCUpdate( hdc );
231 if (!dc) return FALSE;
233 if(PATH_IsPathOpen(dc->path))
234 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
235 else if(dc->funcs->pChord)
236 ret = dc->funcs->pChord(dc,left,top,right,bottom,xstart,ystart,xend,yend);
238 GDI_ReleaseObj( hdc );
239 return ret;
243 /***********************************************************************
244 * Ellipse (GDI.24)
246 BOOL16 WINAPI Ellipse16( HDC16 hdc, INT16 left, INT16 top,
247 INT16 right, INT16 bottom )
249 return Ellipse( hdc, left, top, right, bottom );
253 /***********************************************************************
254 * Ellipse (GDI32.@)
256 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
257 INT right, INT bottom )
259 BOOL ret = FALSE;
260 DC * dc = DC_GetDCUpdate( hdc );
261 if (!dc) return FALSE;
263 if(PATH_IsPathOpen(dc->path))
264 ret = PATH_Ellipse(dc,left,top,right,bottom);
265 else if (dc->funcs->pEllipse)
266 ret = dc->funcs->pEllipse(dc,left,top,right,bottom);
268 GDI_ReleaseObj( hdc );
269 return ret;
273 /***********************************************************************
274 * Rectangle (GDI.27)
276 BOOL16 WINAPI Rectangle16( HDC16 hdc, INT16 left, INT16 top,
277 INT16 right, INT16 bottom )
279 return Rectangle( hdc, left, top, right, bottom );
283 /***********************************************************************
284 * Rectangle (GDI32.@)
286 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
287 INT right, INT bottom )
289 BOOL ret = FALSE;
290 DC * dc = DC_GetDCUpdate( hdc );
291 if (dc)
293 if(PATH_IsPathOpen(dc->path))
294 ret = PATH_Rectangle(dc, left, top, right, bottom);
295 else if (dc->funcs->pRectangle)
296 ret = dc->funcs->pRectangle(dc,left,top,right,bottom);
297 GDI_ReleaseObj( hdc );
299 return ret;
303 /***********************************************************************
304 * RoundRect (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.@)
316 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
317 INT bottom, INT ell_width, INT ell_height )
319 BOOL ret = FALSE;
320 DC *dc = DC_GetDCUpdate( hdc );
322 if (dc)
324 if(PATH_IsPathOpen(dc->path))
325 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
326 else if (dc->funcs->pRoundRect)
327 ret = dc->funcs->pRoundRect(dc,left,top,right,bottom,ell_width,ell_height);
328 GDI_ReleaseObj( hdc );
330 return ret;
333 /***********************************************************************
334 * SetPixel (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.@)
345 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
347 COLORREF ret = 0;
348 DC * dc = DC_GetDCUpdate( hdc );
349 if (dc)
351 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc,x,y,color);
352 GDI_ReleaseObj( hdc );
354 return ret;
357 /***********************************************************************
358 * SetPixelV (GDI32.@)
360 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
362 BOOL ret = FALSE;
363 DC * dc = DC_GetDCUpdate( hdc );
364 if (dc)
366 if (dc->funcs->pSetPixel)
368 dc->funcs->pSetPixel(dc,x,y,color);
369 ret = TRUE;
371 GDI_ReleaseObj( hdc );
373 return ret;
376 /***********************************************************************
377 * GetPixel (GDI.83)
379 COLORREF WINAPI GetPixel16( HDC16 hdc, INT16 x, INT16 y )
381 return GetPixel( hdc, x, y );
385 /***********************************************************************
386 * GetPixel (GDI32.@)
388 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
390 COLORREF ret = CLR_INVALID;
391 DC * dc = DC_GetDCUpdate( hdc );
393 if (dc)
395 /* FIXME: should this be in the graphics driver? */
396 if (PtVisible( hdc, x, y ))
398 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc,x,y);
400 GDI_ReleaseObj( hdc );
402 return ret;
406 /******************************************************************************
407 * ChoosePixelFormat [GDI32.@]
408 * Matches a pixel format to given format
410 * PARAMS
411 * hdc [I] Device context to search for best pixel match
412 * ppfd [I] Pixel format for which a match is sought
414 * RETURNS
415 * Success: Pixel format index closest to given format
416 * Failure: 0
418 INT WINAPI ChoosePixelFormat( HDC hdc, const LPPIXELFORMATDESCRIPTOR ppfd )
420 INT ret = 0;
421 DC * dc = DC_GetDCPtr( hdc );
423 TRACE("(%08x,%p)\n",hdc,ppfd);
425 if (!dc) return 0;
427 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
428 else ret = dc->funcs->pChoosePixelFormat(dc,ppfd);
430 GDI_ReleaseObj( hdc );
431 return ret;
435 /******************************************************************************
436 * SetPixelFormat [GDI32.@]
437 * Sets pixel format of device context
439 * PARAMS
440 * hdc [I] Device context to search for best pixel match
441 * iPixelFormat [I] Pixel format index
442 * ppfd [I] Pixel format for which a match is sought
444 * RETURNS STD
446 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
447 const PIXELFORMATDESCRIPTOR *ppfd)
449 INT bRet = FALSE;
450 DC * dc = DC_GetDCPtr( hdc );
452 TRACE("(%d,%d,%p)\n",hdc,iPixelFormat,ppfd);
454 if (!dc) return 0;
456 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
457 else bRet = dc->funcs->pSetPixelFormat(dc,iPixelFormat,ppfd);
459 GDI_ReleaseObj( hdc );
460 return bRet;
464 /******************************************************************************
465 * GetPixelFormat [GDI32.@]
466 * Gets index of pixel format of DC
468 * PARAMETERS
469 * hdc [I] Device context whose pixel format index is sought
471 * RETURNS
472 * Success: Currently selected pixel format
473 * Failure: 0
475 INT WINAPI GetPixelFormat( HDC hdc )
477 INT ret = 0;
478 DC * dc = DC_GetDCPtr( hdc );
480 TRACE("(%08x)\n",hdc);
482 if (!dc) return 0;
484 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
485 else ret = dc->funcs->pGetPixelFormat(dc);
487 GDI_ReleaseObj( hdc );
488 return ret;
492 /******************************************************************************
493 * DescribePixelFormat [GDI32.@]
494 * Gets info about pixel format from DC
496 * PARAMS
497 * hdc [I] Device context
498 * iPixelFormat [I] Pixel format selector
499 * nBytes [I] Size of buffer
500 * ppfd [O] Pointer to structure to receive pixel format data
502 * RETURNS
503 * Success: Maximum pixel format index of the device context
504 * Failure: 0
506 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
507 LPPIXELFORMATDESCRIPTOR ppfd )
509 INT ret = 0;
510 DC * dc = DC_GetDCPtr( hdc );
512 TRACE("(%08x,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
514 if (!dc) return 0;
516 if (!dc->funcs->pDescribePixelFormat)
518 FIXME(" :stub\n");
519 ppfd->nSize = nBytes;
520 ppfd->nVersion = 1;
521 ret = 3;
523 else ret = dc->funcs->pDescribePixelFormat(dc,iPixelFormat,nBytes,ppfd);
525 GDI_ReleaseObj( hdc );
526 return ret;
530 /******************************************************************************
531 * SwapBuffers [GDI32.@]
532 * Exchanges front and back buffers of window
534 * PARAMS
535 * hdc [I] Device context whose buffers get swapped
537 * RETURNS STD
539 BOOL WINAPI SwapBuffers( HDC hdc )
541 INT bRet = FALSE;
542 DC * dc = DC_GetDCPtr( hdc );
544 TRACE("(%08x)\n",hdc);
546 if (!dc) return TRUE;
548 if (!dc->funcs->pSwapBuffers)
550 FIXME(" :stub\n");
551 bRet = TRUE;
553 else bRet = dc->funcs->pSwapBuffers(dc);
555 GDI_ReleaseObj( hdc );
556 return bRet;
560 /***********************************************************************
561 * PaintRgn (GDI.43)
563 BOOL16 WINAPI PaintRgn16( HDC16 hdc, HRGN16 hrgn )
565 return PaintRgn( hdc, hrgn );
569 /***********************************************************************
570 * PaintRgn (GDI32.@)
572 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
574 BOOL ret = FALSE;
575 DC * dc = DC_GetDCUpdate( hdc );
576 if (dc)
578 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc,hrgn);
579 GDI_ReleaseObj( hdc );
581 return ret;
585 /***********************************************************************
586 * FillRgn (GDI.40)
588 BOOL16 WINAPI FillRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush )
590 return FillRgn( hdc, hrgn, hbrush );
594 /***********************************************************************
595 * FillRgn (GDI32.@)
597 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
599 BOOL retval = FALSE;
600 HBRUSH prevBrush;
601 DC * dc = DC_GetDCUpdate( hdc );
603 if (!dc) return FALSE;
604 if(dc->funcs->pFillRgn)
605 retval = dc->funcs->pFillRgn(dc, hrgn, hbrush);
606 else if ((prevBrush = SelectObject( hdc, hbrush )))
608 retval = PaintRgn( hdc, hrgn );
609 SelectObject( hdc, prevBrush );
611 GDI_ReleaseObj( hdc );
612 return retval;
616 /***********************************************************************
617 * FrameRgn (GDI.41)
619 BOOL16 WINAPI FrameRgn16( HDC16 hdc, HRGN16 hrgn, HBRUSH16 hbrush,
620 INT16 nWidth, INT16 nHeight )
622 return FrameRgn( hdc, hrgn, hbrush, nWidth, nHeight );
626 /***********************************************************************
627 * FrameRgn (GDI32.@)
629 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
630 INT nWidth, INT nHeight )
632 BOOL ret = FALSE;
633 DC *dc = DC_GetDCUpdate( hdc );
635 if (!dc) return FALSE;
636 if(dc->funcs->pFrameRgn)
637 ret = dc->funcs->pFrameRgn( dc, hrgn, hbrush, nWidth, nHeight );
638 else
640 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
641 if (tmp)
643 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
645 FillRgn( hdc, tmp, hbrush );
646 ret = TRUE;
648 DeleteObject( tmp );
651 GDI_ReleaseObj( hdc );
652 return ret;
656 /***********************************************************************
657 * InvertRgn (GDI.42)
659 BOOL16 WINAPI InvertRgn16( HDC16 hdc, HRGN16 hrgn )
661 return InvertRgn( hdc, hrgn );
665 /***********************************************************************
666 * InvertRgn (GDI32.@)
668 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
670 HBRUSH prevBrush;
671 INT prevROP;
672 BOOL retval;
673 DC *dc = DC_GetDCUpdate( hdc );
674 if (!dc) return FALSE;
676 if(dc->funcs->pInvertRgn)
677 retval = dc->funcs->pInvertRgn( dc, hrgn );
678 else
680 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
681 prevROP = SetROP2( hdc, R2_NOT );
682 retval = PaintRgn( hdc, hrgn );
683 SelectObject( hdc, prevBrush );
684 SetROP2( hdc, prevROP );
686 GDI_ReleaseObj( hdc );
687 return retval;
690 /**********************************************************************
691 * Polyline (GDI.37)
693 BOOL16 WINAPI Polyline16( HDC16 hdc, const POINT16* pt, INT16 count )
695 register int i;
696 BOOL16 ret;
697 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
698 count*sizeof(POINT) );
700 if (!pt32) return FALSE;
701 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
702 ret = Polyline(hdc,pt32,count);
703 HeapFree( GetProcessHeap(), 0, pt32 );
704 return ret;
708 /**********************************************************************
709 * Polyline (GDI32.@)
711 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
713 BOOL ret = FALSE;
714 DC * dc = DC_GetDCUpdate( hdc );
715 if (dc)
717 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
718 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc,pt,count);
719 GDI_ReleaseObj( hdc );
721 return ret;
724 /**********************************************************************
725 * PolylineTo (GDI32.@)
727 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
729 DC * dc = DC_GetDCUpdate( hdc );
730 BOOL ret = FALSE;
732 if(!dc) return FALSE;
734 if(PATH_IsPathOpen(dc->path))
735 ret = PATH_PolylineTo(dc, pt, cCount);
737 else if(dc->funcs->pPolylineTo)
738 ret = dc->funcs->pPolylineTo(dc, pt, cCount);
740 else { /* do it using Polyline */
741 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
742 sizeof(POINT) * (cCount + 1) );
743 if (pts)
745 pts[0].x = dc->CursPosX;
746 pts[0].y = dc->CursPosY;
747 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
748 ret = Polyline( hdc, pts, cCount + 1 );
749 HeapFree( GetProcessHeap(), 0, pts );
752 if(ret) {
753 dc->CursPosX = pt[cCount-1].x;
754 dc->CursPosY = pt[cCount-1].y;
756 GDI_ReleaseObj( hdc );
757 return ret;
760 /**********************************************************************
761 * Polygon (GDI.36)
763 BOOL16 WINAPI Polygon16( HDC16 hdc, const POINT16* pt, INT16 count )
765 register int i;
766 BOOL ret;
767 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
768 count*sizeof(POINT) );
770 if (!pt32) return FALSE;
771 for (i=count;i--;) CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
772 ret = Polygon(hdc,pt32,count);
773 HeapFree( GetProcessHeap(), 0, pt32 );
774 return ret;
778 /**********************************************************************
779 * Polygon (GDI32.@)
781 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
783 BOOL ret = FALSE;
784 DC * dc = DC_GetDCUpdate( hdc );
785 if (dc)
787 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
788 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc,pt,count);
789 GDI_ReleaseObj( hdc );
791 return ret;
795 /**********************************************************************
796 * PolyPolygon (GDI.450)
798 BOOL16 WINAPI PolyPolygon16( HDC16 hdc, const POINT16* pt, const INT16* counts,
799 UINT16 polygons )
801 int i,nrpts;
802 LPPOINT pt32;
803 LPINT counts32;
804 BOOL16 ret;
806 nrpts=0;
807 for (i=polygons;i--;)
808 nrpts+=counts[i];
809 pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0, sizeof(POINT)*nrpts);
810 if(pt32 == NULL) return FALSE;
811 for (i=nrpts;i--;)
812 CONV_POINT16TO32(&(pt[i]),&(pt32[i]));
813 counts32 = (LPINT)HeapAlloc( GetProcessHeap(), 0, polygons*sizeof(INT) );
814 if(counts32 == NULL) {
815 HeapFree( GetProcessHeap(), 0, pt32 );
816 return FALSE;
818 for (i=polygons;i--;) counts32[i]=counts[i];
820 ret = PolyPolygon(hdc,pt32,counts32,polygons);
821 HeapFree( GetProcessHeap(), 0, counts32 );
822 HeapFree( GetProcessHeap(), 0, pt32 );
823 return ret;
826 /**********************************************************************
827 * PolyPolygon (GDI32.@)
829 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
830 UINT polygons )
832 BOOL ret = FALSE;
833 DC * dc = DC_GetDCUpdate( hdc );
834 if (dc)
836 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
837 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc,pt,counts,polygons);
838 GDI_ReleaseObj( hdc );
840 return ret;
843 /**********************************************************************
844 * PolyPolyline (GDI32.@)
846 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
847 DWORD polylines )
849 BOOL ret = FALSE;
850 DC * dc = DC_GetDCUpdate( hdc );
851 if (dc)
853 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
854 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc,pt,counts,polylines);
855 GDI_ReleaseObj( hdc );
857 return ret;
860 /**********************************************************************
861 * ExtFloodFill (GDI.372)
863 BOOL16 WINAPI ExtFloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color,
864 UINT16 fillType )
866 return ExtFloodFill( hdc, x, y, color, fillType );
870 /**********************************************************************
871 * ExtFloodFill (GDI32.@)
873 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
874 UINT fillType )
876 BOOL ret = FALSE;
877 DC * dc = DC_GetDCUpdate( hdc );
878 if (dc)
880 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc,x,y,color,fillType);
881 GDI_ReleaseObj( hdc );
883 return ret;
887 /**********************************************************************
888 * FloodFill (GDI.25)
890 BOOL16 WINAPI FloodFill16( HDC16 hdc, INT16 x, INT16 y, COLORREF color )
892 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
896 /**********************************************************************
897 * FloodFill (GDI32.@)
899 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
901 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
905 /******************************************************************************
906 * PolyBezier [GDI.502]
908 BOOL16 WINAPI PolyBezier16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
910 int i;
911 BOOL16 ret;
912 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
913 cPoints*sizeof(POINT) );
914 if(!pt32) return FALSE;
915 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
916 ret= PolyBezier(hDc, pt32, cPoints);
917 HeapFree( GetProcessHeap(), 0, pt32 );
918 return ret;
921 /******************************************************************************
922 * PolyBezierTo [GDI.503]
924 BOOL16 WINAPI PolyBezierTo16( HDC16 hDc, const POINT16* lppt, INT16 cPoints )
926 int i;
927 BOOL16 ret;
928 LPPOINT pt32 = (LPPOINT)HeapAlloc( GetProcessHeap(), 0,
929 cPoints*sizeof(POINT) );
930 if(!pt32) return FALSE;
931 for (i=cPoints;i--;) CONV_POINT16TO32(&(lppt[i]),&(pt32[i]));
932 ret= PolyBezierTo(hDc, pt32, cPoints);
933 HeapFree( GetProcessHeap(), 0, pt32 );
934 return ret;
937 /******************************************************************************
938 * PolyBezier [GDI32.@]
939 * Draws one or more Bezier curves
941 * PARAMS
942 * hDc [I] Handle to device context
943 * lppt [I] Pointer to endpoints and control points
944 * cPoints [I] Count of endpoints and control points
946 * RETURNS STD
948 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
950 BOOL ret = FALSE;
951 DC * dc = DC_GetDCUpdate( hdc );
953 if(!dc) return FALSE;
955 if(PATH_IsPathOpen(dc->path))
956 ret = PATH_PolyBezier(dc, lppt, cPoints);
957 else if (dc->funcs->pPolyBezier)
958 ret = dc->funcs->pPolyBezier(dc, lppt, cPoints);
959 else /* We'll convert it into line segments and draw them using Polyline */
961 POINT *Pts;
962 INT nOut;
964 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
966 TRACE("Pts = %p, no = %d\n", Pts, nOut);
967 ret = Polyline( dc->hSelf, Pts, nOut );
968 HeapFree( GetProcessHeap(), 0, Pts );
972 GDI_ReleaseObj( hdc );
973 return ret;
976 /******************************************************************************
977 * PolyBezierTo [GDI32.@]
978 * Draws one or more Bezier curves
980 * PARAMS
981 * hDc [I] Handle to device context
982 * lppt [I] Pointer to endpoints and control points
983 * cPoints [I] Count of endpoints and control points
985 * RETURNS STD
987 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
989 DC * dc = DC_GetDCUpdate( hdc );
990 BOOL ret;
992 if(!dc) return FALSE;
994 if(PATH_IsPathOpen(dc->path))
995 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
996 else if(dc->funcs->pPolyBezierTo)
997 ret = dc->funcs->pPolyBezierTo(dc, lppt, cPoints);
998 else { /* We'll do it using PolyBezier */
999 POINT *pt;
1000 pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
1001 if(!pt) return FALSE;
1002 pt[0].x = dc->CursPosX;
1003 pt[0].y = dc->CursPosY;
1004 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
1005 ret = PolyBezier(dc->hSelf, pt, cPoints+1);
1006 HeapFree( GetProcessHeap(), 0, pt );
1008 if(ret) {
1009 dc->CursPosX = lppt[cPoints-1].x;
1010 dc->CursPosY = lppt[cPoints-1].y;
1012 GDI_ReleaseObj( hdc );
1013 return ret;
1016 /***********************************************************************
1017 * AngleArc (GDI32.@)
1019 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1021 INT x1,y1,x2,y2, arcdir;
1022 BOOL result;
1023 DC *dc;
1025 if( (signed int)dwRadius < 0 )
1026 return FALSE;
1028 dc = DC_GetDCUpdate( hdc );
1029 if(!dc) return FALSE;
1031 if(dc->funcs->pAngleArc)
1033 result = dc->funcs->pAngleArc( dc, x, y, dwRadius, eStartAngle, eSweepAngle );
1035 GDI_ReleaseObj( hdc );
1036 return result;
1038 GDI_ReleaseObj( hdc );
1040 /* AngleArc always works counterclockwise */
1041 arcdir = GetArcDirection( hdc );
1042 SetArcDirection( hdc, AD_COUNTERCLOCKWISE );
1044 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
1045 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
1046 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1047 y2 = x - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
1049 LineTo( hdc, x1, y1 );
1050 if( eSweepAngle >= 0 )
1051 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1052 x1, y1, x2, y2 );
1053 else
1054 result = Arc( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
1055 x2, y2, x1, y1 );
1057 if( result ) MoveToEx( hdc, x2, y2, NULL );
1058 SetArcDirection( hdc, arcdir );
1059 return result;
1062 /***********************************************************************
1063 * PolyDraw (GDI32.@)
1065 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1066 DWORD cCount)
1068 DC *dc;
1069 BOOL result;
1070 POINT lastmove;
1071 int i;
1073 dc = DC_GetDCUpdate( hdc );
1074 if(!dc) return FALSE;
1076 if(dc->funcs->pPolyDraw)
1078 result = dc->funcs->pPolyDraw( dc, lppt, lpbTypes, cCount );
1079 GDI_ReleaseObj( hdc );
1080 return result;
1082 GDI_ReleaseObj( hdc );
1084 /* check for each bezierto if there are two more points */
1085 for( i = 0; i < cCount; i++ )
1086 if( lpbTypes[i] != PT_MOVETO &&
1087 lpbTypes[i] & PT_BEZIERTO )
1089 if( cCount < i+3 )
1090 return FALSE;
1091 else
1092 i += 2;
1095 /* if no moveto occurs, we will close the figure here */
1096 lastmove.x = dc->CursPosX;
1097 lastmove.y = dc->CursPosY;
1099 /* now let's draw */
1100 for( i = 0; i < cCount; i++ )
1102 if( lpbTypes[i] == PT_MOVETO )
1104 MoveToEx( hdc, lppt[i].x, lppt[i].y, NULL );
1105 lastmove.x = dc->CursPosX;
1106 lastmove.y = dc->CursPosY;
1108 else if( lpbTypes[i] & PT_LINETO )
1109 LineTo( hdc, lppt[i].x, lppt[i].y );
1110 else if( lpbTypes[i] & PT_BEZIERTO )
1112 PolyBezierTo( hdc, &lppt[i], 3 );
1113 i += 2;
1115 else
1116 return FALSE;
1118 if( lpbTypes[i] & PT_CLOSEFIGURE )
1120 if( PATH_IsPathOpen( dc->path ) )
1121 CloseFigure( hdc );
1122 else
1123 LineTo( hdc, lastmove.x, lastmove.y );
1127 return TRUE;
1130 /******************************************************************
1132 * *Very* simple bezier drawing code,
1134 * It uses a recursive algorithm to divide the curve in a series
1135 * of straight line segements. Not ideal but for me sufficient.
1136 * If you are in need for something better look for some incremental
1137 * algorithm.
1139 * 7 July 1998 Rein Klazes
1143 * some macro definitions for bezier drawing
1145 * to avoid trucation errors the coordinates are
1146 * shifted upwards. When used in drawing they are
1147 * shifted down again, including correct rounding
1148 * and avoiding floating point arithmatic
1149 * 4 bits should allow 27 bits coordinates which I saw
1150 * somewere in the win32 doc's
1154 #define BEZIERSHIFTBITS 4
1155 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1156 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1157 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1158 /* maximum depth of recursion */
1159 #define BEZIERMAXDEPTH 8
1161 /* size of array to store points on */
1162 /* enough for one curve */
1163 #define BEZIER_INITBUFSIZE (150)
1165 /* calculate Bezier average, in this case the middle
1166 * correctly rounded...
1167 * */
1169 #define BEZIERMIDDLE(Mid, P1, P2) \
1170 (Mid).x=((P1).x+(P2).x + 1)/2;\
1171 (Mid).y=((P1).y+(P2).y + 1)/2;
1173 /**********************************************************
1174 * BezierCheck helper function to check
1175 * that recursion can be terminated
1176 * Points[0] and Points[3] are begin and endpoint
1177 * Points[1] and Points[2] are control points
1178 * level is the recursion depth
1179 * returns true if the recusion can be terminated
1181 static BOOL BezierCheck( int level, POINT *Points)
1183 INT dx, dy;
1184 dx=Points[3].x-Points[0].x;
1185 dy=Points[3].y-Points[0].y;
1186 if(abs(dy)<=abs(dx)){/* shallow line */
1187 /* check that control points are between begin and end */
1188 if(Points[1].x < Points[0].x){
1189 if(Points[1].x < Points[3].x)
1190 return FALSE;
1191 }else
1192 if(Points[1].x > Points[3].x)
1193 return FALSE;
1194 if(Points[2].x < Points[0].x){
1195 if(Points[2].x < Points[3].x)
1196 return FALSE;
1197 }else
1198 if(Points[2].x > Points[3].x)
1199 return FALSE;
1200 dx=BEZIERSHIFTDOWN(dx);
1201 if(!dx) return TRUE;
1202 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1203 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1204 abs(Points[2].y-Points[0].y-(dy/dx)*
1205 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1206 return FALSE;
1207 else
1208 return TRUE;
1209 }else{ /* steep line */
1210 /* check that control points are between begin and end */
1211 if(Points[1].y < Points[0].y){
1212 if(Points[1].y < Points[3].y)
1213 return FALSE;
1214 }else
1215 if(Points[1].y > Points[3].y)
1216 return FALSE;
1217 if(Points[2].y < Points[0].y){
1218 if(Points[2].y < Points[3].y)
1219 return FALSE;
1220 }else
1221 if(Points[2].y > Points[3].y)
1222 return FALSE;
1223 dy=BEZIERSHIFTDOWN(dy);
1224 if(!dy) return TRUE;
1225 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1226 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1227 abs(Points[2].x-Points[0].x-(dx/dy)*
1228 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1229 return FALSE;
1230 else
1231 return TRUE;
1235 /* Helper for GDI_Bezier.
1236 * Just handles one Bezier, so Points should point to four POINTs
1238 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1239 INT *nPtsOut, INT level )
1241 if(*nPtsOut == *dwOut) {
1242 *dwOut *= 2;
1243 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1244 *dwOut * sizeof(POINT) );
1247 if(!level || BezierCheck(level, Points)) {
1248 if(*nPtsOut == 0) {
1249 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1250 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1251 *nPtsOut = 1;
1253 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1254 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1255 (*nPtsOut) ++;
1256 } else {
1257 POINT Points2[4]; /* for the second recursive call */
1258 Points2[3]=Points[3];
1259 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1260 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1261 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1263 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1264 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1265 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1267 Points2[0]=Points[3];
1269 /* do the two halves */
1270 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1271 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1277 /***********************************************************************
1278 * GDI_Bezier [INTERNAL]
1279 * Calculate line segments that approximate -what microsoft calls- a bezier
1280 * curve.
1281 * The routine recursively divides the curve in two parts until a straight
1282 * line can be drawn
1284 * PARAMS
1286 * Points [I] Ptr to count POINTs which are the end and control points
1287 * of the set of Bezier curves to flatten.
1288 * count [I] Number of Points. Must be 3n+1.
1289 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1290 * lines+1).
1292 * RETURNS
1294 * Ptr to an array of POINTs that contain the lines that approximinate the
1295 * Beziers. The array is allocated on the process heap and it is the caller's
1296 * responsibility to HeapFree it. [this is not a particularly nice interface
1297 * but since we can't know in advance how many points will generate, the
1298 * alternative would be to call the function twice, once to determine the size
1299 * and a second time to do the work - I decided this was too much of a pain].
1301 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1303 POINT *out;
1304 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1306 if((count - 1) % 3 != 0) {
1307 ERR("Invalid no. of points\n");
1308 return NULL;
1310 *nPtsOut = 0;
1311 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1312 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1313 POINT ptBuf[4];
1314 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1315 for(i = 0; i < 4; i++) {
1316 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1317 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1319 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1321 TRACE("Produced %d points\n", *nPtsOut);
1322 return out;