1 /*
2 * GDI drawing functions.
3 *
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
6 * 1999 Huw D M Davies
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 */
22
23 #include "config.h"
24 #include "wine/port.h"
25
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "wingdi.h"
33 #include "winerror.h"
34 #include "gdi_private.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
38
39
40 /***********************************************************************
41 * LineTo (GDI32.@)
42 */
43 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
44 {
45 DC * dc = get_dc_ptr( hdc );
46 BOOL ret;
47
48 if(!dc) return FALSE;
49
50 update_dc( dc );
51 if(PATH_IsPathOpen(dc->path))
52 ret = PATH_LineTo(dc, x, y);
53 else
54 ret = dc->funcs->pLineTo && dc->funcs->pLineTo(dc->physDev,x,y);
55 if(ret) {
56 dc->CursPosX = x;
57 dc->CursPosY = y;
58 }
59 release_dc_ptr( dc );
60 return ret;
61 }
62
63
64 /***********************************************************************
65 * MoveToEx (GDI32.@)
66 */
67 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
68 {
69 BOOL ret = TRUE;
70 DC * dc = get_dc_ptr( hdc );
71
72 if(!dc) return FALSE;
73
74 if(pt) {
75 pt->x = dc->CursPosX;
76 pt->y = dc->CursPosY;
77 }
78 dc->CursPosX = x;
79 dc->CursPosY = y;
80
81 if(PATH_IsPathOpen(dc->path)) ret = PATH_MoveTo(dc);
82 else if (dc->funcs->pMoveTo) ret = dc->funcs->pMoveTo(dc->physDev,x,y);
83 release_dc_ptr( dc );
84 return ret;
85 }
86
87
88 /***********************************************************************
89 * Arc (GDI32.@)
90 */
91 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
92 INT bottom, INT xstart, INT ystart,
93 INT xend, INT yend )
94 {
95 BOOL ret = FALSE;
96 DC * dc = get_dc_ptr( hdc );
97
98 if (dc)
99 {
100 update_dc( dc );
101 if(PATH_IsPathOpen(dc->path))
102 ret = PATH_Arc(dc, left, top, right, bottom, xstart, ystart, xend, yend,0);
103 else if (dc->funcs->pArc)
104 ret = dc->funcs->pArc(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
105 release_dc_ptr( dc );
106 }
107 return ret;
108 }
109
110 /***********************************************************************
111 * ArcTo (GDI32.@)
112 */
113 BOOL WINAPI ArcTo( HDC hdc,
114 INT left, INT top,
115 INT right, INT bottom,
116 INT xstart, INT ystart,
117 INT xend, INT yend )
118 {
119 double width = fabs(right-left),
120 height = fabs(bottom-top),
121 xradius = width/2,
122 yradius = height/2,
123 xcenter = right > left ? left+xradius : right+xradius,
124 ycenter = bottom > top ? top+yradius : bottom+yradius,
125 angle;
126 BOOL result;
127 DC * dc = get_dc_ptr( hdc );
128 if(!dc) return FALSE;
129
130 update_dc( dc );
131 if(PATH_IsPathOpen(dc->path))
132 result = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,-1);
133 else if(dc->funcs->pArcTo)
134 result = dc->funcs->pArcTo( dc->physDev, left, top, right, bottom,
135 xstart, ystart, xend, yend );
136 else /* We'll draw a line from the current position to the starting point of the arc, then draw the arc */
137 {
138 angle = atan2(((ystart-ycenter)/height),
139 ((xstart-xcenter)/width));
140 LineTo(hdc, GDI_ROUND(xcenter+(cos(angle)*xradius)),
141 GDI_ROUND(ycenter+(sin(angle)*yradius)));
142 result = Arc(hdc, left, top, right, bottom, xstart, ystart, xend, yend);
143 }
144 if (result) {
145 angle = atan2(((yend-ycenter)/height),
146 ((xend-xcenter)/width));
147 dc->CursPosX = GDI_ROUND(xcenter+(cos(angle)*xradius));
148 dc->CursPosY = GDI_ROUND(ycenter+(sin(angle)*yradius));
149 }
150 release_dc_ptr( dc );
151 return result;
152 }
153
154
155 /***********************************************************************
156 * Pie (GDI32.@)
157 */
158 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
159 INT right, INT bottom, INT xstart, INT ystart,
160 INT xend, INT yend )
161 {
162 BOOL ret = FALSE;
163 DC * dc = get_dc_ptr( hdc );
164 if (!dc) return FALSE;
165
166 update_dc( dc );
167 if(PATH_IsPathOpen(dc->path))
168 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,2);
169 else if(dc->funcs->pPie)
170 ret = dc->funcs->pPie(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
171
172 release_dc_ptr( dc );
173 return ret;
174 }
175
176
177 /***********************************************************************
178 * Chord (GDI32.@)
179 */
180 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
181 INT right, INT bottom, INT xstart, INT ystart,
182 INT xend, INT yend )
183 {
184 BOOL ret = FALSE;
185 DC * dc = get_dc_ptr( hdc );
186 if (!dc) return FALSE;
187
188 update_dc( dc );
189 if(PATH_IsPathOpen(dc->path))
190 ret = PATH_Arc(dc,left,top,right,bottom,xstart,ystart,xend,yend,1);
191 else if(dc->funcs->pChord)
192 ret = dc->funcs->pChord(dc->physDev,left,top,right,bottom,xstart,ystart,xend,yend);
193
194 release_dc_ptr( dc );
195 return ret;
196 }
197
198
199 /***********************************************************************
200 * Ellipse (GDI32.@)
201 */
202 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
203 INT right, INT bottom )
204 {
205 BOOL ret = FALSE;
206 DC * dc = get_dc_ptr( hdc );
207 if (!dc) return FALSE;
208
209 update_dc( dc );
210 if(PATH_IsPathOpen(dc->path))
211 ret = PATH_Ellipse(dc,left,top,right,bottom);
212 else if (dc->funcs->pEllipse)
213 ret = dc->funcs->pEllipse(dc->physDev,left,top,right,bottom);
214
215 release_dc_ptr( dc );
216 return ret;
217 }
218
219
220 /***********************************************************************
221 * Rectangle (GDI32.@)
222 */
223 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
224 INT right, INT bottom )
225 {
226 BOOL ret = FALSE;
227 DC * dc = get_dc_ptr( hdc );
228
229 if (dc)
230 {
231 update_dc( dc );
232 if(PATH_IsPathOpen(dc->path))
233 ret = PATH_Rectangle(dc, left, top, right, bottom);
234 else if (dc->funcs->pRectangle)
235 ret = dc->funcs->pRectangle(dc->physDev,left,top,right,bottom);
236 release_dc_ptr( dc );
237 }
238 return ret;
239 }
240
241
242 /***********************************************************************
243 * RoundRect (GDI32.@)
244 */
245 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
246 INT bottom, INT ell_width, INT ell_height )
247 {
248 BOOL ret = FALSE;
249 DC *dc = get_dc_ptr( hdc );
250
251 if (dc)
252 {
253 update_dc( dc );
254 if(PATH_IsPathOpen(dc->path))
255 ret = PATH_RoundRect(dc,left,top,right,bottom,ell_width,ell_height);
256 else if (dc->funcs->pRoundRect)
257 ret = dc->funcs->pRoundRect(dc->physDev,left,top,right,bottom,ell_width,ell_height);
258 release_dc_ptr( dc );
259 }
260 return ret;
261 }
262
263 /***********************************************************************
264 * SetPixel (GDI32.@)
265 */
266 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
267 {
268 COLORREF ret = 0;
269 DC * dc = get_dc_ptr( hdc );
270
271 if (dc)
272 {
273 update_dc( dc );
274 if (dc->funcs->pSetPixel) ret = dc->funcs->pSetPixel(dc->physDev,x,y,color);
275 release_dc_ptr( dc );
276 }
277 return ret;
278 }
279
280 /***********************************************************************
281 * SetPixelV (GDI32.@)
282 */
283 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
284 {
285 BOOL ret = FALSE;
286 DC * dc = get_dc_ptr( hdc );
287
288 if (dc)
289 {
290 update_dc( dc );
291 if (dc->funcs->pSetPixel)
292 {
293 dc->funcs->pSetPixel(dc->physDev,x,y,color);
294 ret = TRUE;
295 }
296 release_dc_ptr( dc );
297 }
298 return ret;
299 }
300
301 /***********************************************************************
302 * GetPixel (GDI32.@)
303 */
304 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
305 {
306 COLORREF ret = CLR_INVALID;
307 DC * dc = get_dc_ptr( hdc );
308
309 if (dc)
310 {
311 update_dc( dc );
312 /* FIXME: should this be in the graphics driver? */
313 if (PtVisible( hdc, x, y ))
314 {
315 if (dc->funcs->pGetPixel) ret = dc->funcs->pGetPixel(dc->physDev,x,y);
316 }
317 release_dc_ptr( dc );
318 }
319 return ret;
320 }
321
322
323 /******************************************************************************
324 * ChoosePixelFormat [GDI32.@]
325 * Matches a pixel format to given format
326 *
327 * PARAMS
328 * hdc [I] Device context to search for best pixel match
329 * ppfd [I] Pixel format for which a match is sought
330 *
331 * RETURNS
332 * Success: Pixel format index closest to given format
333 * Failure: 0
334 */
335 INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
336 {
337 INT ret = 0;
338 DC * dc = get_dc_ptr( hdc );
339
340 TRACE("(%p,%p)\n",hdc,ppfd);
341
342 if (!dc) return 0;
343
344 if (!dc->funcs->pChoosePixelFormat) FIXME(" :stub\n");
345 else ret = dc->funcs->pChoosePixelFormat(dc->physDev,ppfd);
346
347 release_dc_ptr( dc );
348 return ret;
349 }
350
351
352 /******************************************************************************
353 * SetPixelFormat [GDI32.@]
354 * Sets pixel format of device context
355 *
356 * PARAMS
357 * hdc [I] Device context to search for best pixel match
358 * iPixelFormat [I] Pixel format index
359 * ppfd [I] Pixel format for which a match is sought
360 *
361 * RETURNS
362 * Success: TRUE
363 * Failure: FALSE
364 */
365 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
366 const PIXELFORMATDESCRIPTOR *ppfd)
367 {
368 INT bRet = FALSE;
369 DC * dc = get_dc_ptr( hdc );
370
371 TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
372
373 if (!dc) return 0;
374
375 if (!dc->funcs->pSetPixelFormat) FIXME(" :stub\n");
376 else bRet = dc->funcs->pSetPixelFormat(dc->physDev,iPixelFormat,ppfd);
377
378 release_dc_ptr( dc );
379 return bRet;
380 }
381
382
383 /******************************************************************************
384 * GetPixelFormat [GDI32.@]
385 * Gets index of pixel format of DC
386 *
387 * PARAMETERS
388 * hdc [I] Device context whose pixel format index is sought
389 *
390 * RETURNS
391 * Success: Currently selected pixel format
392 * Failure: 0
393 */
394 INT WINAPI GetPixelFormat( HDC hdc )
395 {
396 INT ret = 0;
397 DC * dc = get_dc_ptr( hdc );
398
399 TRACE("(%p)\n",hdc);
400
401 if (!dc) return 0;
402
403 update_dc( dc );
404 if (!dc->funcs->pGetPixelFormat) FIXME(" :stub\n");
405 else ret = dc->funcs->pGetPixelFormat(dc->physDev);
406
407 release_dc_ptr( dc );
408 return ret;
409 }
410
411
412 /******************************************************************************
413 * DescribePixelFormat [GDI32.@]
414 * Gets info about pixel format from DC
415 *
416 * PARAMS
417 * hdc [I] Device context
418 * iPixelFormat [I] Pixel format selector
419 * nBytes [I] Size of buffer
420 * ppfd [O] Pointer to structure to receive pixel format data
421 *
422 * RETURNS
423 * Success: Maximum pixel format index of the device context
424 * Failure: 0
425 */
426 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
427 LPPIXELFORMATDESCRIPTOR ppfd )
428 {
429 INT ret = 0;
430 DC * dc = get_dc_ptr( hdc );
431
432 TRACE("(%p,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
433
434 if (!dc) return 0;
435
436 if (!dc->funcs->pDescribePixelFormat)
437 {
438 FIXME(" :stub\n");
439 ppfd->nSize = nBytes;
440 ppfd->nVersion = 1;
441 ret = 3;
442 }
443 else ret = dc->funcs->pDescribePixelFormat(dc->physDev,iPixelFormat,nBytes,ppfd);
444
445 release_dc_ptr( dc );
446 return ret;
447 }
448
449
450 /******************************************************************************
451 * SwapBuffers [GDI32.@]
452 * Exchanges front and back buffers of window
453 *
454 * PARAMS
455 * hdc [I] Device context whose buffers get swapped
456 *
457 * RETURNS
458 * Success: TRUE
459 * Failure: FALSE
460 */
461 BOOL WINAPI SwapBuffers( HDC hdc )
462 {
463 INT bRet = FALSE;
464 DC * dc = get_dc_ptr( hdc );
465
466 TRACE("(%p)\n",hdc);
467
468 if (!dc) return TRUE;
469
470 update_dc( dc );
471 if (!dc->funcs->pSwapBuffers)
472 {
473 FIXME(" :stub\n");
474 bRet = TRUE;
475 }
476 else bRet = dc->funcs->pSwapBuffers(dc->physDev);
477
478 release_dc_ptr( dc );
479 return bRet;
480 }
481
482
483 /***********************************************************************
484 * PaintRgn (GDI32.@)
485 */
486 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
487 {
488 BOOL ret = FALSE;
489 DC * dc = get_dc_ptr( hdc );
490
491 if (dc)
492 {
493 update_dc( dc );
494 if (dc->funcs->pPaintRgn) ret = dc->funcs->pPaintRgn(dc->physDev,hrgn);
495 release_dc_ptr( dc );
496 }
497 return ret;
498 }
499
500
501 /***********************************************************************
502 * FillRgn (GDI32.@)
503 */
504 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
505 {
506 BOOL retval = FALSE;
507 HBRUSH prevBrush;
508 DC * dc = get_dc_ptr( hdc );
509
510 if (!dc) return FALSE;
511 if(dc->funcs->pFillRgn)
512 {
513 update_dc( dc );
514 retval = dc->funcs->pFillRgn(dc->physDev, hrgn, hbrush);
515 }
516 else if ((prevBrush = SelectObject( hdc, hbrush )))
517 {
518 retval = PaintRgn( hdc, hrgn );
519 SelectObject( hdc, prevBrush );
520 }
521 release_dc_ptr( dc );
522 return retval;
523 }
524
525
526 /***********************************************************************
527 * FrameRgn (GDI32.@)
528 */
529 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
530 INT nWidth, INT nHeight )
531 {
532 BOOL ret = FALSE;
533 DC *dc = get_dc_ptr( hdc );
534
535 if (!dc) return FALSE;
536
537 if(dc->funcs->pFrameRgn)
538 {
539 update_dc( dc );
540 ret = dc->funcs->pFrameRgn( dc->physDev, hrgn, hbrush, nWidth, nHeight );
541 }
542 else
543 {
544 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
545 if (tmp)
546 {
547 if (REGION_FrameRgn( tmp, hrgn, nWidth, nHeight ))
548 {
549 FillRgn( hdc, tmp, hbrush );
550 ret = TRUE;
551 }
552 DeleteObject( tmp );
553 }
554 }
555 release_dc_ptr( dc );
556 return ret;
557 }
558
559
560 /***********************************************************************
561 * InvertRgn (GDI32.@)
562 */
563 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
564 {
565 HBRUSH prevBrush;
566 INT prevROP;
567 BOOL retval;
568 DC *dc = get_dc_ptr( hdc );
569 if (!dc) return FALSE;
570
571 if(dc->funcs->pInvertRgn)
572 {
573 update_dc( dc );
574 retval = dc->funcs->pInvertRgn( dc->physDev, hrgn );
575 }
576 else
577 {
578 prevBrush = SelectObject( hdc, GetStockObject(BLACK_BRUSH) );
579 prevROP = SetROP2( hdc, R2_NOT );
580 retval = PaintRgn( hdc, hrgn );
581 SelectObject( hdc, prevBrush );
582 SetROP2( hdc, prevROP );
583 }
584 release_dc_ptr( dc );
585 return retval;
586 }
587
588
589 /**********************************************************************
590 * Polyline (GDI32.@)
591 */
592 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
593 {
594 BOOL ret = FALSE;
595 DC * dc = get_dc_ptr( hdc );
596
597 if (dc)
598 {
599 update_dc( dc );
600 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polyline(dc, pt, count);
601 else if (dc->funcs->pPolyline) ret = dc->funcs->pPolyline(dc->physDev,pt,count);
602 release_dc_ptr( dc );
603 }
604 return ret;
605 }
606
607 /**********************************************************************
608 * PolylineTo (GDI32.@)
609 */
610 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
611 {
612 DC * dc = get_dc_ptr( hdc );
613 BOOL ret = FALSE;
614
615 if(!dc) return FALSE;
616
617 if(PATH_IsPathOpen(dc->path))
618 {
619 update_dc( dc );
620 ret = PATH_PolylineTo(dc, pt, cCount);
621 }
622 else if(dc->funcs->pPolylineTo)
623 {
624 update_dc( dc );
625 ret = dc->funcs->pPolylineTo(dc->physDev, pt, cCount);
626 }
627 else /* do it using Polyline */
628 {
629 POINT *pts = HeapAlloc( GetProcessHeap(), 0,
630 sizeof(POINT) * (cCount + 1) );
631 if (pts)
632 {
633 pts[0].x = dc->CursPosX;
634 pts[0].y = dc->CursPosY;
635 memcpy( pts + 1, pt, sizeof(POINT) * cCount );
636 ret = Polyline( hdc, pts, cCount + 1 );
637 HeapFree( GetProcessHeap(), 0, pts );
638 }
639 }
640 if(ret) {
641 dc->CursPosX = pt[cCount-1].x;
642 dc->CursPosY = pt[cCount-1].y;
643 }
644 release_dc_ptr( dc );
645 return ret;
646 }
647
648
649 /**********************************************************************
650 * Polygon (GDI32.@)
651 */
652 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
653 {
654 BOOL ret = FALSE;
655 DC * dc = get_dc_ptr( hdc );
656
657 if (dc)
658 {
659 update_dc( dc );
660 if (PATH_IsPathOpen(dc->path)) ret = PATH_Polygon(dc, pt, count);
661 else if (dc->funcs->pPolygon) ret = dc->funcs->pPolygon(dc->physDev,pt,count);
662 release_dc_ptr( dc );
663 }
664 return ret;
665 }
666
667
668 /**********************************************************************
669 * PolyPolygon (GDI32.@)
670 */
671 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
672 UINT polygons )
673 {
674 BOOL ret = FALSE;
675 DC * dc = get_dc_ptr( hdc );
676
677 if (dc)
678 {
679 update_dc( dc );
680 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolygon(dc, pt, counts, polygons);
681 else if (dc->funcs->pPolyPolygon) ret = dc->funcs->pPolyPolygon(dc->physDev,pt,counts,polygons);
682 release_dc_ptr( dc );
683 }
684 return ret;
685 }
686
687 /**********************************************************************
688 * PolyPolyline (GDI32.@)
689 */
690 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
691 DWORD polylines )
692 {
693 BOOL ret = FALSE;
694 DC * dc = get_dc_ptr( hdc );
695
696 if (dc)
697 {
698 update_dc( dc );
699 if (PATH_IsPathOpen(dc->path)) ret = PATH_PolyPolyline(dc, pt, counts, polylines);
700 else if (dc->funcs->pPolyPolyline) ret = dc->funcs->pPolyPolyline(dc->physDev,pt,counts,polylines);
701 release_dc_ptr( dc );
702 }
703 return ret;
704 }
705
706 /**********************************************************************
707 * ExtFloodFill (GDI32.@)
708 */
709 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
710 UINT fillType )
711 {
712 BOOL ret = FALSE;
713 DC * dc = get_dc_ptr( hdc );
714
715 if (dc)
716 {
717 update_dc( dc );
718 if (dc->funcs->pExtFloodFill) ret = dc->funcs->pExtFloodFill(dc->physDev,x,y,color,fillType);
719 release_dc_ptr( dc );
720 }
721 return ret;
722 }
723
724
725 /**********************************************************************
726 * FloodFill (GDI32.@)
727 */
728 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
729 {
730 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
731 }
732
733
734 /******************************************************************************
735 * PolyBezier [GDI32.@]
736 * Draws one or more Bezier curves
737 *
738 * PARAMS
739 * hDc [I] Handle to device context
740 * lppt [I] Pointer to endpoints and control points
741 * cPoints [I] Count of endpoints and control points
742 *
743 * RETURNS
744 * Success: TRUE
745 * Failure: FALSE
746 */
747 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
748 {
749 BOOL ret = FALSE;
750 DC * dc;
751
752 /* cPoints must be 3 * n + 1 (where n>=1) */
753 if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
754
755 dc = get_dc_ptr( hdc );
756 if(!dc) return FALSE;
757
758 if(PATH_IsPathOpen(dc->path))
759 {
760 update_dc( dc );
761 ret = PATH_PolyBezier(dc, lppt, cPoints);
762 }
763 else if (dc->funcs->pPolyBezier)
764 {
765 update_dc( dc );
766 ret = dc->funcs->pPolyBezier(dc->physDev, lppt, cPoints);
767 }
768 else /* We'll convert it into line segments and draw them using Polyline */
769 {
770 POINT *Pts;
771 INT nOut;
772
773 if ((Pts = GDI_Bezier( lppt, cPoints, &nOut )))
774 {
775 TRACE("Pts = %p, no = %d\n", Pts, nOut);
776 ret = Polyline( hdc, Pts, nOut );
777 HeapFree( GetProcessHeap(), 0, Pts );
778 }
779 }
780
781 release_dc_ptr( dc );
782 return ret;
783 }
784
785 /******************************************************************************
786 * PolyBezierTo [GDI32.@]
787 * Draws one or more Bezier curves
788 *
789 * PARAMS
790 * hDc [I] Handle to device context
791 * lppt [I] Pointer to endpoints and control points
792 * cPoints [I] Count of endpoints and control points
793 *
794 * RETURNS
795 * Success: TRUE
796 * Failure: FALSE
797 */
798 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
799 {
800 DC * dc;
801 BOOL ret = FALSE;
802
803 /* cbPoints must be 3 * n (where n>=1) */
804 if (!cPoints || (cPoints % 3) != 0) return FALSE;
805
806 dc = get_dc_ptr( hdc );
807 if(!dc) return FALSE;
808
809 if(PATH_IsPathOpen(dc->path))
810 {
811 update_dc( dc );
812 ret = PATH_PolyBezierTo(dc, lppt, cPoints);
813 }
814 else if(dc->funcs->pPolyBezierTo)
815 {
816 update_dc( dc );
817 ret = dc->funcs->pPolyBezierTo(dc->physDev, lppt, cPoints);
818 }
819 else /* We'll do it using PolyBezier */
820 {
821 POINT *pt = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (cPoints + 1) );
822 if(pt)
823 {
824 pt[0].x = dc->CursPosX;
825 pt[0].y = dc->CursPosY;
826 memcpy(pt + 1, lppt, sizeof(POINT) * cPoints);
827 ret = PolyBezier(hdc, pt, cPoints+1);
828 HeapFree( GetProcessHeap(), 0, pt );
829 }
830 }
831 if(ret) {
832 dc->CursPosX = lppt[cPoints-1].x;
833 dc->CursPosY = lppt[cPoints-1].y;
834 }
835 release_dc_ptr( dc );
836 return ret;
837 }
838
839 /***********************************************************************
840 * AngleArc (GDI32.@)
841 */
842 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
843 {
844 INT x1,y1,x2,y2, arcdir;
845 BOOL result;
846 DC *dc;
847
848 if( (signed int)dwRadius < 0 )
849 return FALSE;
850
851 dc = get_dc_ptr( hdc );
852 if(!dc) return FALSE;
853
854 /* Calculate the end point */
855 x2 = x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
856 y2 = y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius;
857
858 if(!PATH_IsPathOpen(dc->path) && dc->funcs->pAngleArc)
859 {
860 update_dc( dc );
861 result = dc->funcs->pAngleArc( dc->physDev, x, y, dwRadius, eStartAngle, eSweepAngle );
862 }
863 else { /* do it using ArcTo */
864 x1 = x + cos(eStartAngle*M_PI/180) * dwRadius;
865 y1 = y - sin(eStartAngle*M_PI/180) * dwRadius;
866
867 arcdir = SetArcDirection( hdc, eSweepAngle >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE);
868 result = ArcTo( hdc, x-dwRadius, y-dwRadius, x+dwRadius, y+dwRadius,
869 x1, y1, x2, y2 );
870 SetArcDirection( hdc, arcdir );
871 }
872 if (result) {
873 dc->CursPosX = x2;
874 dc->CursPosY = y2;
875 }
876 release_dc_ptr( dc );
877 return result;
878 }
879
880 /***********************************************************************
881 * PolyDraw (GDI32.@)
882 */
883 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
884 DWORD cCount)
885 {
886 DC *dc;
887 BOOL result = FALSE;
888 POINT * line_pts = NULL, * bzr_pts = NULL, bzr[4];
889 INT i, num_pts, num_bzr_pts, space, size;
890
891 dc = get_dc_ptr( hdc );
892 if(!dc) return FALSE;
893
894 if( PATH_IsPathOpen( dc->path ) )
895 {
896 update_dc( dc );
897 result = PATH_PolyDraw(dc, lppt, lpbTypes, cCount);
898 }
899 else if(dc->funcs->pPolyDraw)
900 {
901 update_dc( dc );
902 result = dc->funcs->pPolyDraw( dc->physDev, lppt, lpbTypes, cCount );
903 }
904 else {
905 /* check for valid point types */
906 for(i = 0; i < cCount; i++) {
907 switch(lpbTypes[i]) {
908 case PT_MOVETO:
909 case PT_LINETO | PT_CLOSEFIGURE:
910 case PT_LINETO:
911 break;
912 case PT_BEZIERTO:
913 if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) &&
914 ((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO)){
915 i += 2;
916 break;
917 }
918 default:
919 goto end;
920 }
921 }
922
923 space = cCount + 300;
924 line_pts = HeapAlloc(GetProcessHeap(), 0, space * sizeof(POINT));
925 num_pts = 1;
926
927 line_pts[0].x = dc->CursPosX;
928 line_pts[0].y = dc->CursPosY;
929
930 for(i = 0; i < cCount; i++) {
931 switch(lpbTypes[i]) {
932 case PT_MOVETO:
933 if(num_pts >= 2)
934 Polyline(hdc, line_pts, num_pts);
935 num_pts = 0;
936 line_pts[num_pts++] = lppt[i];
937 break;
938 case PT_LINETO:
939 case (PT_LINETO | PT_CLOSEFIGURE):
940 line_pts[num_pts++] = lppt[i];
941 break;
942 case PT_BEZIERTO:
943 bzr[0].x = line_pts[num_pts - 1].x;
944 bzr[0].y = line_pts[num_pts - 1].y;
945 memcpy(&bzr[1], &lppt[i], 3 * sizeof(POINT));
946
947 bzr_pts = GDI_Bezier(bzr, 4, &num_bzr_pts);
948
949 size = num_pts + (cCount - i) + num_bzr_pts;
950 if(space < size){
951 space = size * 2;
952 line_pts = HeapReAlloc(GetProcessHeap(), 0, line_pts,
953 space * sizeof(POINT));
954 }
955 memcpy(&line_pts[num_pts], &bzr_pts[1],
956 (num_bzr_pts - 1) * sizeof(POINT));
957 num_pts += num_bzr_pts - 1;
958 HeapFree(GetProcessHeap(), 0, bzr_pts);
959 i += 2;
960 break;
961 default:
962 goto end;
963 }
964
965 if(lpbTypes[i] & PT_CLOSEFIGURE)
966 line_pts[num_pts++] = line_pts[0];
967 }
968
969 if(num_pts >= 2)
970 Polyline(hdc, line_pts, num_pts);
971
972 MoveToEx(hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL);
973 HeapFree(GetProcessHeap(), 0, line_pts);
974 result = TRUE;
975 }
976
977 end:
978 release_dc_ptr( dc );
979 return result;
980 }
981
982
983 /**********************************************************************
984 * LineDDA (GDI32.@)
985 */
986 BOOL WINAPI LineDDA(INT nXStart, INT nYStart,