msvcrt: Implement _wfreopen_s.
[wine/testsucceed.git] / dlls / gdi32 / painting.c
blob97a5fc09eed0a146cb0b24219ef9dc0db40c6535
1 /*
2 * GDI drawing functions.
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
6 * 1999 Huw D M Davies
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.
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.
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <stdlib.h>
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"
37 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
40 /***********************************************************************
41 * null driver fallback implementations
44 BOOL nulldrv_AngleArc( PHYSDEV dev, INT x, INT y, DWORD radius, FLOAT start, FLOAT sweep )
46 INT x1 = GDI_ROUND( x + cos( start * M_PI / 180 ) * radius );
47 INT y1 = GDI_ROUND( y - sin( start * M_PI / 180 ) * radius );
48 INT x2 = GDI_ROUND( x + cos( (start + sweep) * M_PI / 180) * radius );
49 INT y2 = GDI_ROUND( y - sin( (start + sweep) * M_PI / 180) * radius );
50 INT arcdir = SetArcDirection( dev->hdc, sweep >= 0 ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE );
51 BOOL ret = ArcTo( dev->hdc, x - radius, y - radius, x + radius, y + radius, x1, y1, x2, y2 );
52 SetArcDirection( dev->hdc, arcdir );
53 return ret;
56 BOOL nulldrv_ArcTo( PHYSDEV dev, INT left, INT top, INT right, INT bottom,
57 INT xstart, INT ystart, INT xend, INT yend )
59 INT width = abs( right - left );
60 INT height = abs( bottom - top );
61 double xradius = width / 2.0;
62 double yradius = height / 2.0;
63 double xcenter = right > left ? left + xradius : right + xradius;
64 double ycenter = bottom > top ? top + yradius : bottom + yradius;
65 double angle;
67 if (!height || !width) return FALSE;
68 /* draw a line from the current position to the starting point of the arc, then draw the arc */
69 angle = atan2( (ystart - ycenter) / height, (xstart - xcenter) / width );
70 LineTo( dev->hdc, GDI_ROUND( xcenter + cos(angle) * xradius ),
71 GDI_ROUND( ycenter + sin(angle) * yradius ));
72 return Arc( dev->hdc, left, top, right, bottom, xstart, ystart, xend, yend );
75 BOOL nulldrv_FillRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush )
77 BOOL ret = FALSE;
78 HBRUSH prev;
80 if ((prev = SelectObject( dev->hdc, brush )))
82 ret = PaintRgn( dev->hdc, rgn );
83 SelectObject( dev->hdc, prev );
85 return ret;
88 BOOL nulldrv_FrameRgn( PHYSDEV dev, HRGN rgn, HBRUSH brush, INT width, INT height )
90 BOOL ret = FALSE;
91 HRGN tmp = CreateRectRgn( 0, 0, 0, 0 );
93 if (tmp)
95 if (REGION_FrameRgn( tmp, rgn, width, height )) ret = FillRgn( dev->hdc, tmp, brush );
96 DeleteObject( tmp );
98 return ret;
101 BOOL nulldrv_InvertRgn( PHYSDEV dev, HRGN rgn )
103 HBRUSH prev_brush = SelectObject( dev->hdc, GetStockObject(BLACK_BRUSH) );
104 INT prev_rop = SetROP2( dev->hdc, R2_NOT );
105 BOOL ret = PaintRgn( dev->hdc, rgn );
106 SelectObject( dev->hdc, prev_brush );
107 SetROP2( dev->hdc, prev_rop );
108 return ret;
111 BOOL nulldrv_PolyBezier( PHYSDEV dev, const POINT *points, DWORD count )
113 BOOL ret = FALSE;
114 POINT *pts;
115 INT n;
117 if ((pts = GDI_Bezier( points, count, &n )))
119 ret = Polyline( dev->hdc, pts, n );
120 HeapFree( GetProcessHeap(), 0, pts );
122 return ret;
125 BOOL nulldrv_PolyBezierTo( PHYSDEV dev, const POINT *points, DWORD count )
127 BOOL ret = FALSE;
128 POINT *pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) );
130 if (pts)
132 GetCurrentPositionEx( dev->hdc, &pts[0] );
133 memcpy( pts + 1, points, sizeof(POINT) * count );
134 ret = PolyBezier( dev->hdc, pts, count + 1 );
135 HeapFree( GetProcessHeap(), 0, pts );
137 return ret;
140 BOOL nulldrv_PolyDraw( PHYSDEV dev, const POINT *points, const BYTE *types, DWORD count )
142 POINT *line_pts = NULL, *bzr_pts = NULL, bzr[4];
143 INT i, num_pts, num_bzr_pts, space, size;
145 /* check for valid point types */
146 for (i = 0; i < count; i++)
148 switch (types[i])
150 case PT_MOVETO:
151 case PT_LINETO | PT_CLOSEFIGURE:
152 case PT_LINETO:
153 break;
154 case PT_BEZIERTO:
155 if((i + 2 < count) && (types[i + 1] == PT_BEZIERTO) &&
156 ((types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
158 i += 2;
159 break;
161 default:
162 return FALSE;
166 space = count + 300;
167 line_pts = HeapAlloc( GetProcessHeap(), 0, space * sizeof(POINT) );
168 num_pts = 1;
170 GetCurrentPositionEx( dev->hdc, &line_pts[0] );
171 for (i = 0; i < count; i++)
173 switch (types[i])
175 case PT_MOVETO:
176 if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
177 num_pts = 0;
178 line_pts[num_pts++] = points[i];
179 break;
180 case PT_LINETO:
181 case (PT_LINETO | PT_CLOSEFIGURE):
182 line_pts[num_pts++] = points[i];
183 break;
184 case PT_BEZIERTO:
185 bzr[0].x = line_pts[num_pts - 1].x;
186 bzr[0].y = line_pts[num_pts - 1].y;
187 memcpy( &bzr[1], &points[i], 3 * sizeof(POINT) );
189 if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
191 size = num_pts + (count - i) + num_bzr_pts;
192 if (space < size)
194 space = size * 2;
195 line_pts = HeapReAlloc( GetProcessHeap(), 0, line_pts, space * sizeof(POINT) );
197 memcpy( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
198 num_pts += num_bzr_pts - 1;
199 HeapFree( GetProcessHeap(), 0, bzr_pts );
201 i += 2;
202 break;
204 if (types[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
207 if (num_pts >= 2) Polyline( dev->hdc, line_pts, num_pts );
208 MoveToEx( dev->hdc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
209 HeapFree( GetProcessHeap(), 0, line_pts );
210 return TRUE;
213 BOOL nulldrv_PolylineTo( PHYSDEV dev, const POINT *points, INT count )
215 BOOL ret = FALSE;
216 POINT *pts;
218 if (!count) return FALSE;
219 if ((pts = HeapAlloc( GetProcessHeap(), 0, sizeof(POINT) * (count + 1) )))
221 GetCurrentPositionEx( dev->hdc, &pts[0] );
222 memcpy( pts + 1, points, sizeof(POINT) * count );
223 ret = Polyline( dev->hdc, pts, count + 1 );
224 HeapFree( GetProcessHeap(), 0, pts );
226 return ret;
229 BOOL nulldrv_GradientFill( PHYSDEV dev, TRIVERTEX *vert_array, ULONG nvert,
230 void * grad_array, ULONG ngrad, ULONG mode )
232 unsigned int i;
234 switch(mode)
236 case GRADIENT_FILL_RECT_H:
237 for(i = 0; i < ngrad; i++)
239 GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
240 TRIVERTEX *v1 = vert_array + rect->UpperLeft;
241 TRIVERTEX *v2 = vert_array + rect->LowerRight;
242 int y1 = v1->y < v2->y ? v1->y : v2->y;
243 int y2 = v2->y > v1->y ? v2->y : v1->y;
244 int x, dx;
245 if (v1->x > v2->x)
247 TRIVERTEX *t = v2;
248 v2 = v1;
249 v1 = t;
251 dx = v2->x - v1->x;
252 for (x = 0; x < dx; x++)
254 POINT pts[2];
255 HPEN hPen, hOldPen;
257 hPen = CreatePen( PS_SOLID, 1, RGB(
258 (v1->Red * (dx - x) + v2->Red * x) / dx >> 8,
259 (v1->Green * (dx - x) + v2->Green * x) / dx >> 8,
260 (v1->Blue * (dx - x) + v2->Blue * x) / dx >> 8));
261 hOldPen = SelectObject( dev->hdc, hPen );
262 pts[0].x = v1->x + x;
263 pts[0].y = y1;
264 pts[1].x = v1->x + x;
265 pts[1].y = y2;
266 Polyline( dev->hdc, &pts[0], 2 );
267 DeleteObject( SelectObject(dev->hdc, hOldPen ) );
270 break;
271 case GRADIENT_FILL_RECT_V:
272 for(i = 0; i < ngrad; i++)
274 GRADIENT_RECT *rect = ((GRADIENT_RECT *)grad_array) + i;
275 TRIVERTEX *v1 = vert_array + rect->UpperLeft;
276 TRIVERTEX *v2 = vert_array + rect->LowerRight;
277 int x1 = v1->x < v2->x ? v1->x : v2->x;
278 int x2 = v2->x > v1->x ? v2->x : v1->x;
279 int y, dy;
280 if (v1->y > v2->y)
282 TRIVERTEX *t = v2;
283 v2 = v1;
284 v1 = t;
286 dy = v2->y - v1->y;
287 for (y = 0; y < dy; y++)
289 POINT pts[2];
290 HPEN hPen, hOldPen;
292 hPen = CreatePen( PS_SOLID, 1, RGB(
293 (v1->Red * (dy - y) + v2->Red * y) / dy >> 8,
294 (v1->Green * (dy - y) + v2->Green * y) / dy >> 8,
295 (v1->Blue * (dy - y) + v2->Blue * y) / dy >> 8));
296 hOldPen = SelectObject( dev->hdc, hPen );
297 pts[0].x = x1;
298 pts[0].y = v1->y + y;
299 pts[1].x = x2;
300 pts[1].y = v1->y + y;
301 Polyline( dev->hdc, &pts[0], 2 );
302 DeleteObject( SelectObject(dev->hdc, hOldPen ) );
305 break;
306 case GRADIENT_FILL_TRIANGLE:
307 for (i = 0; i < ngrad; i++)
309 GRADIENT_TRIANGLE *tri = ((GRADIENT_TRIANGLE *)grad_array) + i;
310 TRIVERTEX *v1 = vert_array + tri->Vertex1;
311 TRIVERTEX *v2 = vert_array + tri->Vertex2;
312 TRIVERTEX *v3 = vert_array + tri->Vertex3;
313 int y, dy;
315 if (v1->y > v2->y)
316 { TRIVERTEX *t = v1; v1 = v2; v2 = t; }
317 if (v2->y > v3->y)
319 TRIVERTEX *t = v2; v2 = v3; v3 = t;
320 if (v1->y > v2->y)
321 { t = v1; v1 = v2; v2 = t; }
323 /* v1->y <= v2->y <= v3->y */
325 dy = v3->y - v1->y;
326 for (y = 0; y < dy; y++)
328 /* v1->y <= y < v3->y */
329 TRIVERTEX *v = y < (v2->y - v1->y) ? v1 : v3;
330 /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
331 int dy2 = v2->y - v->y;
332 int y2 = y + v1->y - v->y;
334 int x1 = (v3->x * y + v1->x * (dy - y )) / dy;
335 int x2 = (v2->x * y2 + v-> x * (dy2 - y2)) / dy2;
336 int r1 = (v3->Red * y + v1->Red * (dy - y )) / dy;
337 int r2 = (v2->Red * y2 + v-> Red * (dy2 - y2)) / dy2;
338 int g1 = (v3->Green * y + v1->Green * (dy - y )) / dy;
339 int g2 = (v2->Green * y2 + v-> Green * (dy2 - y2)) / dy2;
340 int b1 = (v3->Blue * y + v1->Blue * (dy - y )) / dy;
341 int b2 = (v2->Blue * y2 + v-> Blue * (dy2 - y2)) / dy2;
343 int x;
344 if (x1 < x2)
346 int dx = x2 - x1;
347 for (x = 0; x < dx; x++)
348 SetPixel (dev->hdc, x + x1, y + v1->y, RGB(
349 (r1 * (dx - x) + r2 * x) / dx >> 8,
350 (g1 * (dx - x) + g2 * x) / dx >> 8,
351 (b1 * (dx - x) + b2 * x) / dx >> 8));
353 else
355 int dx = x1 - x2;
356 for (x = 0; x < dx; x++)
357 SetPixel (dev->hdc, x + x2, y + v1->y, RGB(
358 (r2 * (dx - x) + r1 * x) / dx >> 8,
359 (g2 * (dx - x) + g1 * x) / dx >> 8,
360 (b2 * (dx - x) + b1 * x) / dx >> 8));
364 break;
365 default:
366 return FALSE;
369 return TRUE;
372 /***********************************************************************
373 * LineTo (GDI32.@)
375 BOOL WINAPI LineTo( HDC hdc, INT x, INT y )
377 DC * dc = get_dc_ptr( hdc );
378 PHYSDEV physdev;
379 BOOL ret;
381 if(!dc) return FALSE;
383 update_dc( dc );
384 physdev = GET_DC_PHYSDEV( dc, pLineTo );
385 ret = physdev->funcs->pLineTo( physdev, x, y );
387 if(ret) {
388 dc->CursPosX = x;
389 dc->CursPosY = y;
391 release_dc_ptr( dc );
392 return ret;
396 /***********************************************************************
397 * MoveToEx (GDI32.@)
399 BOOL WINAPI MoveToEx( HDC hdc, INT x, INT y, LPPOINT pt )
401 BOOL ret;
402 PHYSDEV physdev;
403 DC * dc = get_dc_ptr( hdc );
405 if(!dc) return FALSE;
407 if(pt) {
408 pt->x = dc->CursPosX;
409 pt->y = dc->CursPosY;
411 dc->CursPosX = x;
412 dc->CursPosY = y;
414 physdev = GET_DC_PHYSDEV( dc, pMoveTo );
415 ret = physdev->funcs->pMoveTo( physdev, x, y );
416 release_dc_ptr( dc );
417 return ret;
421 /***********************************************************************
422 * Arc (GDI32.@)
424 BOOL WINAPI Arc( HDC hdc, INT left, INT top, INT right,
425 INT bottom, INT xstart, INT ystart,
426 INT xend, INT yend )
428 BOOL ret = FALSE;
429 DC * dc = get_dc_ptr( hdc );
431 if (dc)
433 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pArc );
434 update_dc( dc );
435 ret = physdev->funcs->pArc( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
436 release_dc_ptr( dc );
438 return ret;
441 /***********************************************************************
442 * ArcTo (GDI32.@)
444 BOOL WINAPI ArcTo( HDC hdc,
445 INT left, INT top,
446 INT right, INT bottom,
447 INT xstart, INT ystart,
448 INT xend, INT yend )
450 double width = fabs(right-left),
451 height = fabs(bottom-top),
452 xradius = width/2,
453 yradius = height/2,
454 xcenter = right > left ? left+xradius : right+xradius,
455 ycenter = bottom > top ? top+yradius : bottom+yradius,
456 angle;
457 PHYSDEV physdev;
458 BOOL result;
459 DC * dc = get_dc_ptr( hdc );
460 if(!dc) return FALSE;
462 update_dc( dc );
463 physdev = GET_DC_PHYSDEV( dc, pArcTo );
464 result = physdev->funcs->pArcTo( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
466 if (result) {
467 angle = atan2(((yend-ycenter)/height),
468 ((xend-xcenter)/width));
469 dc->CursPosX = GDI_ROUND(xcenter+(cos(angle)*xradius));
470 dc->CursPosY = GDI_ROUND(ycenter+(sin(angle)*yradius));
472 release_dc_ptr( dc );
473 return result;
477 /***********************************************************************
478 * Pie (GDI32.@)
480 BOOL WINAPI Pie( HDC hdc, INT left, INT top,
481 INT right, INT bottom, INT xstart, INT ystart,
482 INT xend, INT yend )
484 BOOL ret;
485 PHYSDEV physdev;
486 DC * dc = get_dc_ptr( hdc );
487 if (!dc) return FALSE;
489 update_dc( dc );
490 physdev = GET_DC_PHYSDEV( dc, pPie );
491 ret = physdev->funcs->pPie( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
492 release_dc_ptr( dc );
493 return ret;
497 /***********************************************************************
498 * Chord (GDI32.@)
500 BOOL WINAPI Chord( HDC hdc, INT left, INT top,
501 INT right, INT bottom, INT xstart, INT ystart,
502 INT xend, INT yend )
504 BOOL ret;
505 PHYSDEV physdev;
506 DC * dc = get_dc_ptr( hdc );
507 if (!dc) return FALSE;
509 update_dc( dc );
510 physdev = GET_DC_PHYSDEV( dc, pChord );
511 ret = physdev->funcs->pChord( physdev, left, top, right, bottom, xstart, ystart, xend, yend );
512 release_dc_ptr( dc );
513 return ret;
517 /***********************************************************************
518 * Ellipse (GDI32.@)
520 BOOL WINAPI Ellipse( HDC hdc, INT left, INT top,
521 INT right, INT bottom )
523 BOOL ret;
524 PHYSDEV physdev;
525 DC * dc = get_dc_ptr( hdc );
526 if (!dc) return FALSE;
528 update_dc( dc );
529 physdev = GET_DC_PHYSDEV( dc, pEllipse );
530 ret = physdev->funcs->pEllipse( physdev, left, top, right, bottom );
531 release_dc_ptr( dc );
532 return ret;
536 /***********************************************************************
537 * Rectangle (GDI32.@)
539 BOOL WINAPI Rectangle( HDC hdc, INT left, INT top,
540 INT right, INT bottom )
542 BOOL ret = FALSE;
543 DC * dc = get_dc_ptr( hdc );
545 if (dc)
547 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRectangle );
548 update_dc( dc );
549 ret = physdev->funcs->pRectangle( physdev, left, top, right, bottom );
550 release_dc_ptr( dc );
552 return ret;
556 /***********************************************************************
557 * RoundRect (GDI32.@)
559 BOOL WINAPI RoundRect( HDC hdc, INT left, INT top, INT right,
560 INT bottom, INT ell_width, INT ell_height )
562 BOOL ret = FALSE;
563 DC *dc = get_dc_ptr( hdc );
565 if (dc)
567 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRoundRect );
568 update_dc( dc );
569 ret = physdev->funcs->pRoundRect( physdev, left, top, right, bottom, ell_width, ell_height );
570 release_dc_ptr( dc );
572 return ret;
575 /***********************************************************************
576 * SetPixel (GDI32.@)
578 COLORREF WINAPI SetPixel( HDC hdc, INT x, INT y, COLORREF color )
580 COLORREF ret = 0;
581 DC * dc = get_dc_ptr( hdc );
583 if (dc)
585 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
586 update_dc( dc );
587 ret = physdev->funcs->pSetPixel( physdev, x, y, color );
588 release_dc_ptr( dc );
590 return ret;
593 /***********************************************************************
594 * SetPixelV (GDI32.@)
596 BOOL WINAPI SetPixelV( HDC hdc, INT x, INT y, COLORREF color )
598 BOOL ret = FALSE;
599 DC * dc = get_dc_ptr( hdc );
601 if (dc)
603 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixel );
604 update_dc( dc );
605 physdev->funcs->pSetPixel( physdev, x, y, color );
606 ret = TRUE;
607 release_dc_ptr( dc );
609 return ret;
612 /***********************************************************************
613 * GetPixel (GDI32.@)
615 COLORREF WINAPI GetPixel( HDC hdc, INT x, INT y )
617 COLORREF ret = CLR_INVALID;
618 DC * dc = get_dc_ptr( hdc );
620 if (dc)
622 update_dc( dc );
623 /* FIXME: should this be in the graphics driver? */
624 if (PtVisible( hdc, x, y ))
626 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixel );
627 ret = physdev->funcs->pGetPixel( physdev, x, y );
629 release_dc_ptr( dc );
631 return ret;
635 /******************************************************************************
636 * ChoosePixelFormat [GDI32.@]
637 * Matches a pixel format to given format
639 * PARAMS
640 * hdc [I] Device context to search for best pixel match
641 * ppfd [I] Pixel format for which a match is sought
643 * RETURNS
644 * Success: Pixel format index closest to given format
645 * Failure: 0
647 INT WINAPI ChoosePixelFormat( HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd )
649 INT ret = 0;
650 DC * dc = get_dc_ptr( hdc );
652 TRACE("(%p,%p)\n",hdc,ppfd);
654 if (dc)
656 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pChoosePixelFormat );
657 ret = physdev->funcs->pChoosePixelFormat( physdev, ppfd );
658 release_dc_ptr( dc );
660 return ret;
664 /******************************************************************************
665 * SetPixelFormat [GDI32.@]
666 * Sets pixel format of device context
668 * PARAMS
669 * hdc [I] Device context to search for best pixel match
670 * iPixelFormat [I] Pixel format index
671 * ppfd [I] Pixel format for which a match is sought
673 * RETURNS
674 * Success: TRUE
675 * Failure: FALSE
677 BOOL WINAPI SetPixelFormat( HDC hdc, INT iPixelFormat,
678 const PIXELFORMATDESCRIPTOR *ppfd)
680 INT bRet = FALSE;
681 DC * dc = get_dc_ptr( hdc );
683 TRACE("(%p,%d,%p)\n",hdc,iPixelFormat,ppfd);
685 if (dc)
687 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSetPixelFormat );
688 update_dc( dc );
689 bRet = physdev->funcs->pSetPixelFormat( physdev, iPixelFormat, ppfd );
690 release_dc_ptr( dc );
692 return bRet;
696 /******************************************************************************
697 * GetPixelFormat [GDI32.@]
698 * Gets index of pixel format of DC
700 * PARAMETERS
701 * hdc [I] Device context whose pixel format index is sought
703 * RETURNS
704 * Success: Currently selected pixel format
705 * Failure: 0
707 INT WINAPI GetPixelFormat( HDC hdc )
709 INT ret = 0;
710 DC * dc = get_dc_ptr( hdc );
712 TRACE("(%p)\n",hdc);
714 if (dc)
716 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetPixelFormat );
717 update_dc( dc );
718 ret = physdev->funcs->pGetPixelFormat( physdev );
719 release_dc_ptr( dc );
721 return ret;
725 /******************************************************************************
726 * DescribePixelFormat [GDI32.@]
727 * Gets info about pixel format from DC
729 * PARAMS
730 * hdc [I] Device context
731 * iPixelFormat [I] Pixel format selector
732 * nBytes [I] Size of buffer
733 * ppfd [O] Pointer to structure to receive pixel format data
735 * RETURNS
736 * Success: Maximum pixel format index of the device context
737 * Failure: 0
739 INT WINAPI DescribePixelFormat( HDC hdc, INT iPixelFormat, UINT nBytes,
740 LPPIXELFORMATDESCRIPTOR ppfd )
742 INT ret = 0;
743 DC * dc = get_dc_ptr( hdc );
745 TRACE("(%p,%d,%d,%p): stub\n",hdc,iPixelFormat,nBytes,ppfd);
747 if (dc)
749 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pDescribePixelFormat );
750 update_dc( dc );
751 ret = physdev->funcs->pDescribePixelFormat( physdev, iPixelFormat, nBytes, ppfd );
752 release_dc_ptr( dc );
754 return ret;
758 /******************************************************************************
759 * SwapBuffers [GDI32.@]
760 * Exchanges front and back buffers of window
762 * PARAMS
763 * hdc [I] Device context whose buffers get swapped
765 * RETURNS
766 * Success: TRUE
767 * Failure: FALSE
769 BOOL WINAPI SwapBuffers( HDC hdc )
771 INT bRet = FALSE;
772 DC * dc = get_dc_ptr( hdc );
774 TRACE("(%p)\n",hdc);
776 if (dc)
778 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSwapBuffers );
779 update_dc( dc );
780 bRet = physdev->funcs->pSwapBuffers( physdev );
781 release_dc_ptr( dc );
783 return bRet;
787 /***********************************************************************
788 * PaintRgn (GDI32.@)
790 BOOL WINAPI PaintRgn( HDC hdc, HRGN hrgn )
792 BOOL ret = FALSE;
793 DC * dc = get_dc_ptr( hdc );
795 if (dc)
797 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPaintRgn );
798 update_dc( dc );
799 ret = physdev->funcs->pPaintRgn( physdev, hrgn );
800 release_dc_ptr( dc );
802 return ret;
806 /***********************************************************************
807 * FillRgn (GDI32.@)
809 BOOL WINAPI FillRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush )
811 BOOL retval = FALSE;
812 DC * dc = get_dc_ptr( hdc );
814 if (dc)
816 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFillRgn );
817 update_dc( dc );
818 retval = physdev->funcs->pFillRgn( physdev, hrgn, hbrush );
819 release_dc_ptr( dc );
821 return retval;
825 /***********************************************************************
826 * FrameRgn (GDI32.@)
828 BOOL WINAPI FrameRgn( HDC hdc, HRGN hrgn, HBRUSH hbrush,
829 INT nWidth, INT nHeight )
831 BOOL ret = FALSE;
832 DC *dc = get_dc_ptr( hdc );
834 if (dc)
836 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pFrameRgn );
837 update_dc( dc );
838 ret = physdev->funcs->pFrameRgn( physdev, hrgn, hbrush, nWidth, nHeight );
839 release_dc_ptr( dc );
841 return ret;
845 /***********************************************************************
846 * InvertRgn (GDI32.@)
848 BOOL WINAPI InvertRgn( HDC hdc, HRGN hrgn )
850 BOOL ret = FALSE;
851 DC *dc = get_dc_ptr( hdc );
853 if (dc)
855 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pInvertRgn );
856 update_dc( dc );
857 ret = physdev->funcs->pInvertRgn( physdev, hrgn );
858 release_dc_ptr( dc );
860 return ret;
864 /**********************************************************************
865 * Polyline (GDI32.@)
867 BOOL WINAPI Polyline( HDC hdc, const POINT* pt, INT count )
869 BOOL ret = FALSE;
870 DC * dc = get_dc_ptr( hdc );
872 if (dc)
874 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyline );
875 update_dc( dc );
876 ret = physdev->funcs->pPolyline( physdev, pt, count );
877 release_dc_ptr( dc );
879 return ret;
882 /**********************************************************************
883 * PolylineTo (GDI32.@)
885 BOOL WINAPI PolylineTo( HDC hdc, const POINT* pt, DWORD cCount )
887 DC * dc = get_dc_ptr( hdc );
888 PHYSDEV physdev;
889 BOOL ret;
891 if(!dc) return FALSE;
893 update_dc( dc );
894 physdev = GET_DC_PHYSDEV( dc, pPolylineTo );
895 ret = physdev->funcs->pPolylineTo( physdev, pt, cCount );
897 if (ret && cCount)
899 dc->CursPosX = pt[cCount-1].x;
900 dc->CursPosY = pt[cCount-1].y;
902 release_dc_ptr( dc );
903 return ret;
907 /**********************************************************************
908 * Polygon (GDI32.@)
910 BOOL WINAPI Polygon( HDC hdc, const POINT* pt, INT count )
912 BOOL ret = FALSE;
913 DC * dc = get_dc_ptr( hdc );
915 if (dc)
917 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolygon );
918 update_dc( dc );
919 ret = physdev->funcs->pPolygon( physdev, pt, count );
920 release_dc_ptr( dc );
922 return ret;
926 /**********************************************************************
927 * PolyPolygon (GDI32.@)
929 BOOL WINAPI PolyPolygon( HDC hdc, const POINT* pt, const INT* counts,
930 UINT polygons )
932 BOOL ret = FALSE;
933 DC * dc = get_dc_ptr( hdc );
935 if (dc)
937 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolygon );
938 update_dc( dc );
939 ret = physdev->funcs->pPolyPolygon( physdev, pt, counts, polygons );
940 release_dc_ptr( dc );
942 return ret;
945 /**********************************************************************
946 * PolyPolyline (GDI32.@)
948 BOOL WINAPI PolyPolyline( HDC hdc, const POINT* pt, const DWORD* counts,
949 DWORD polylines )
951 BOOL ret = FALSE;
952 DC * dc = get_dc_ptr( hdc );
954 if (dc)
956 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pPolyPolyline );
957 update_dc( dc );
958 ret = physdev->funcs->pPolyPolyline( physdev, pt, counts, polylines );
959 release_dc_ptr( dc );
961 return ret;
964 /**********************************************************************
965 * ExtFloodFill (GDI32.@)
967 BOOL WINAPI ExtFloodFill( HDC hdc, INT x, INT y, COLORREF color,
968 UINT fillType )
970 BOOL ret = FALSE;
971 DC * dc = get_dc_ptr( hdc );
973 if (dc)
975 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pExtFloodFill );
977 update_dc( dc );
978 ret = physdev->funcs->pExtFloodFill( physdev, x, y, color, fillType );
979 release_dc_ptr( dc );
981 return ret;
985 /**********************************************************************
986 * FloodFill (GDI32.@)
988 BOOL WINAPI FloodFill( HDC hdc, INT x, INT y, COLORREF color )
990 return ExtFloodFill( hdc, x, y, color, FLOODFILLBORDER );
994 /******************************************************************************
995 * PolyBezier [GDI32.@]
996 * Draws one or more Bezier curves
998 * PARAMS
999 * hDc [I] Handle to device context
1000 * lppt [I] Pointer to endpoints and control points
1001 * cPoints [I] Count of endpoints and control points
1003 * RETURNS
1004 * Success: TRUE
1005 * Failure: FALSE
1007 BOOL WINAPI PolyBezier( HDC hdc, const POINT* lppt, DWORD cPoints )
1009 PHYSDEV physdev;
1010 BOOL ret;
1011 DC * dc;
1013 /* cPoints must be 3 * n + 1 (where n>=1) */
1014 if (cPoints == 1 || (cPoints % 3) != 1) return FALSE;
1016 dc = get_dc_ptr( hdc );
1017 if(!dc) return FALSE;
1019 update_dc( dc );
1020 physdev = GET_DC_PHYSDEV( dc, pPolyBezier );
1021 ret = physdev->funcs->pPolyBezier( physdev, lppt, cPoints );
1022 release_dc_ptr( dc );
1023 return ret;
1026 /******************************************************************************
1027 * PolyBezierTo [GDI32.@]
1028 * Draws one or more Bezier curves
1030 * PARAMS
1031 * hDc [I] Handle to device context
1032 * lppt [I] Pointer to endpoints and control points
1033 * cPoints [I] Count of endpoints and control points
1035 * RETURNS
1036 * Success: TRUE
1037 * Failure: FALSE
1039 BOOL WINAPI PolyBezierTo( HDC hdc, const POINT* lppt, DWORD cPoints )
1041 DC * dc;
1042 BOOL ret;
1043 PHYSDEV physdev;
1045 /* cbPoints must be 3 * n (where n>=1) */
1046 if (!cPoints || (cPoints % 3) != 0) return FALSE;
1048 dc = get_dc_ptr( hdc );
1049 if(!dc) return FALSE;
1051 update_dc( dc );
1052 physdev = GET_DC_PHYSDEV( dc, pPolyBezierTo );
1053 ret = physdev->funcs->pPolyBezierTo( physdev, lppt, cPoints );
1055 if(ret) {
1056 dc->CursPosX = lppt[cPoints-1].x;
1057 dc->CursPosY = lppt[cPoints-1].y;
1059 release_dc_ptr( dc );
1060 return ret;
1063 /***********************************************************************
1064 * AngleArc (GDI32.@)
1066 BOOL WINAPI AngleArc(HDC hdc, INT x, INT y, DWORD dwRadius, FLOAT eStartAngle, FLOAT eSweepAngle)
1068 PHYSDEV physdev;
1069 BOOL result;
1070 DC *dc;
1072 if( (signed int)dwRadius < 0 )
1073 return FALSE;
1075 dc = get_dc_ptr( hdc );
1076 if(!dc) return FALSE;
1078 update_dc( dc );
1079 physdev = GET_DC_PHYSDEV( dc, pAngleArc );
1080 result = physdev->funcs->pAngleArc( physdev, x, y, dwRadius, eStartAngle, eSweepAngle );
1082 if (result) {
1083 dc->CursPosX = GDI_ROUND( x + cos((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
1084 dc->CursPosY = GDI_ROUND( y - sin((eStartAngle+eSweepAngle)*M_PI/180) * dwRadius );
1086 release_dc_ptr( dc );
1087 return result;
1090 /***********************************************************************
1091 * PolyDraw (GDI32.@)
1093 BOOL WINAPI PolyDraw(HDC hdc, const POINT *lppt, const BYTE *lpbTypes,
1094 DWORD cCount)
1096 DC *dc = get_dc_ptr( hdc );
1097 PHYSDEV physdev;
1098 BOOL result;
1100 if(!dc) return FALSE;
1102 update_dc( dc );
1103 physdev = GET_DC_PHYSDEV( dc, pPolyDraw );
1104 result = physdev->funcs->pPolyDraw( physdev, lppt, lpbTypes, cCount );
1105 release_dc_ptr( dc );
1106 return result;
1110 /**********************************************************************
1111 * LineDDA (GDI32.@)
1113 BOOL WINAPI LineDDA(INT nXStart, INT nYStart, INT nXEnd, INT nYEnd,
1114 LINEDDAPROC callback, LPARAM lParam )
1116 INT xadd = 1, yadd = 1;
1117 INT err,erradd;
1118 INT cnt;
1119 INT dx = nXEnd - nXStart;
1120 INT dy = nYEnd - nYStart;
1122 if (dx < 0)
1124 dx = -dx;
1125 xadd = -1;
1127 if (dy < 0)
1129 dy = -dy;
1130 yadd = -1;
1132 if (dx > dy) /* line is "more horizontal" */
1134 err = 2*dy - dx; erradd = 2*dy - 2*dx;
1135 for(cnt = 0;cnt < dx; cnt++)
1137 callback(nXStart,nYStart,lParam);
1138 if (err > 0)
1140 nYStart += yadd;
1141 err += erradd;
1143 else err += 2*dy;
1144 nXStart += xadd;
1147 else /* line is "more vertical" */
1149 err = 2*dx - dy; erradd = 2*dx - 2*dy;
1150 for(cnt = 0;cnt < dy; cnt++)
1152 callback(nXStart,nYStart,lParam);
1153 if (err > 0)
1155 nXStart += xadd;
1156 err += erradd;
1158 else err += 2*dx;
1159 nYStart += yadd;
1162 return TRUE;
1166 /******************************************************************
1168 * *Very* simple bezier drawing code,
1170 * It uses a recursive algorithm to divide the curve in a series
1171 * of straight line segments. Not ideal but sufficient for me.
1172 * If you are in need for something better look for some incremental
1173 * algorithm.
1175 * 7 July 1998 Rein Klazes
1179 * some macro definitions for bezier drawing
1181 * to avoid truncation errors the coordinates are
1182 * shifted upwards. When used in drawing they are
1183 * shifted down again, including correct rounding
1184 * and avoiding floating point arithmetic
1185 * 4 bits should allow 27 bits coordinates which I saw
1186 * somewhere in the win32 doc's
1190 #define BEZIERSHIFTBITS 4
1191 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1192 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1193 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1194 /* maximum depth of recursion */
1195 #define BEZIERMAXDEPTH 8
1197 /* size of array to store points on */
1198 /* enough for one curve */
1199 #define BEZIER_INITBUFSIZE (150)
1201 /* calculate Bezier average, in this case the middle
1202 * correctly rounded...
1203 * */
1205 #define BEZIERMIDDLE(Mid, P1, P2) \
1206 (Mid).x=((P1).x+(P2).x + 1)/2;\
1207 (Mid).y=((P1).y+(P2).y + 1)/2;
1209 /**********************************************************
1210 * BezierCheck helper function to check
1211 * that recursion can be terminated
1212 * Points[0] and Points[3] are begin and endpoint
1213 * Points[1] and Points[2] are control points
1214 * level is the recursion depth
1215 * returns true if the recursion can be terminated
1217 static BOOL BezierCheck( int level, POINT *Points)
1219 INT dx, dy;
1220 dx=Points[3].x-Points[0].x;
1221 dy=Points[3].y-Points[0].y;
1222 if(abs(dy)<=abs(dx)){/* shallow line */
1223 /* check that control points are between begin and end */
1224 if(Points[1].x < Points[0].x){
1225 if(Points[1].x < Points[3].x)
1226 return FALSE;
1227 }else
1228 if(Points[1].x > Points[3].x)
1229 return FALSE;
1230 if(Points[2].x < Points[0].x){
1231 if(Points[2].x < Points[3].x)
1232 return FALSE;
1233 }else
1234 if(Points[2].x > Points[3].x)
1235 return FALSE;
1236 dx=BEZIERSHIFTDOWN(dx);
1237 if(!dx) return TRUE;
1238 if(abs(Points[1].y-Points[0].y-(dy/dx)*
1239 BEZIERSHIFTDOWN(Points[1].x-Points[0].x)) > BEZIERPIXEL ||
1240 abs(Points[2].y-Points[0].y-(dy/dx)*
1241 BEZIERSHIFTDOWN(Points[2].x-Points[0].x)) > BEZIERPIXEL )
1242 return FALSE;
1243 else
1244 return TRUE;
1245 }else{ /* steep line */
1246 /* check that control points are between begin and end */
1247 if(Points[1].y < Points[0].y){
1248 if(Points[1].y < Points[3].y)
1249 return FALSE;
1250 }else
1251 if(Points[1].y > Points[3].y)
1252 return FALSE;
1253 if(Points[2].y < Points[0].y){
1254 if(Points[2].y < Points[3].y)
1255 return FALSE;
1256 }else
1257 if(Points[2].y > Points[3].y)
1258 return FALSE;
1259 dy=BEZIERSHIFTDOWN(dy);
1260 if(!dy) return TRUE;
1261 if(abs(Points[1].x-Points[0].x-(dx/dy)*
1262 BEZIERSHIFTDOWN(Points[1].y-Points[0].y)) > BEZIERPIXEL ||
1263 abs(Points[2].x-Points[0].x-(dx/dy)*
1264 BEZIERSHIFTDOWN(Points[2].y-Points[0].y)) > BEZIERPIXEL )
1265 return FALSE;
1266 else
1267 return TRUE;
1271 /* Helper for GDI_Bezier.
1272 * Just handles one Bezier, so Points should point to four POINTs
1274 static void GDI_InternalBezier( POINT *Points, POINT **PtsOut, INT *dwOut,
1275 INT *nPtsOut, INT level )
1277 if(*nPtsOut == *dwOut) {
1278 *dwOut *= 2;
1279 *PtsOut = HeapReAlloc( GetProcessHeap(), 0, *PtsOut,
1280 *dwOut * sizeof(POINT) );
1283 if(!level || BezierCheck(level, Points)) {
1284 if(*nPtsOut == 0) {
1285 (*PtsOut)[0].x = BEZIERSHIFTDOWN(Points[0].x);
1286 (*PtsOut)[0].y = BEZIERSHIFTDOWN(Points[0].y);
1287 *nPtsOut = 1;
1289 (*PtsOut)[*nPtsOut].x = BEZIERSHIFTDOWN(Points[3].x);
1290 (*PtsOut)[*nPtsOut].y = BEZIERSHIFTDOWN(Points[3].y);
1291 (*nPtsOut) ++;
1292 } else {
1293 POINT Points2[4]; /* for the second recursive call */
1294 Points2[3]=Points[3];
1295 BEZIERMIDDLE(Points2[2], Points[2], Points[3]);
1296 BEZIERMIDDLE(Points2[0], Points[1], Points[2]);
1297 BEZIERMIDDLE(Points2[1],Points2[0],Points2[2]);
1299 BEZIERMIDDLE(Points[1], Points[0], Points[1]);
1300 BEZIERMIDDLE(Points[2], Points[1], Points2[0]);
1301 BEZIERMIDDLE(Points[3], Points[2], Points2[1]);
1303 Points2[0]=Points[3];
1305 /* do the two halves */
1306 GDI_InternalBezier(Points, PtsOut, dwOut, nPtsOut, level-1);
1307 GDI_InternalBezier(Points2, PtsOut, dwOut, nPtsOut, level-1);
1313 /***********************************************************************
1314 * GDI_Bezier [INTERNAL]
1315 * Calculate line segments that approximate -what microsoft calls- a bezier
1316 * curve.
1317 * The routine recursively divides the curve in two parts until a straight
1318 * line can be drawn
1320 * PARAMS
1322 * Points [I] Ptr to count POINTs which are the end and control points
1323 * of the set of Bezier curves to flatten.
1324 * count [I] Number of Points. Must be 3n+1.
1325 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1326 * lines+1).
1328 * RETURNS
1330 * Ptr to an array of POINTs that contain the lines that approximate the
1331 * Beziers. The array is allocated on the process heap and it is the caller's
1332 * responsibility to HeapFree it. [this is not a particularly nice interface
1333 * but since we can't know in advance how many points we will generate, the
1334 * alternative would be to call the function twice, once to determine the size
1335 * and a second time to do the work - I decided this was too much of a pain].
1337 POINT *GDI_Bezier( const POINT *Points, INT count, INT *nPtsOut )
1339 POINT *out;
1340 INT Bezier, dwOut = BEZIER_INITBUFSIZE, i;
1342 if (count == 1 || (count - 1) % 3 != 0) {
1343 ERR("Invalid no. of points %d\n", count);
1344 return NULL;
1346 *nPtsOut = 0;
1347 out = HeapAlloc( GetProcessHeap(), 0, dwOut * sizeof(POINT));
1348 for(Bezier = 0; Bezier < (count-1)/3; Bezier++) {
1349 POINT ptBuf[4];
1350 memcpy(ptBuf, Points + Bezier * 3, sizeof(POINT) * 4);
1351 for(i = 0; i < 4; i++) {
1352 ptBuf[i].x = BEZIERSHIFTUP(ptBuf[i].x);
1353 ptBuf[i].y = BEZIERSHIFTUP(ptBuf[i].y);
1355 GDI_InternalBezier( ptBuf, &out, &dwOut, nPtsOut, BEZIERMAXDEPTH );
1357 TRACE("Produced %d points\n", *nPtsOut);
1358 return out;
1361 /******************************************************************************
1362 * GdiGradientFill (GDI32.@)
1364 * FIXME: we don't support the Alpha channel properly
1366 BOOL WINAPI GdiGradientFill( HDC hdc, TRIVERTEX *vert_array, ULONG nvert,
1367 void * grad_array, ULONG ngrad, ULONG mode )
1369 DC *dc = get_dc_ptr( hdc );
1370 PHYSDEV physdev;
1371 BOOL ret;
1373 TRACE("%p vert_array:%p nvert:%d grad_array:%p ngrad:%d\n", hdc, vert_array, nvert, grad_array, ngrad);
1375 if (!dc) return FALSE;
1377 update_dc( dc );
1378 physdev = GET_DC_PHYSDEV( dc, pGradientFill );
1379 ret = physdev->funcs->pGradientFill( physdev, vert_array, nvert, grad_array, ngrad, mode );
1380 release_dc_ptr( dc );
1381 return ret;
1384 /******************************************************************************
1385 * GdiDrawStream (GDI32.@)
1388 BOOL WINAPI GdiDrawStream( HDC hdc, ULONG in, void * pvin )
1390 FIXME("stub: %p, %d, %p\n", hdc, in, pvin);
1391 return FALSE;