2 * GDI drawing functions.
4 * Copyright 1993, 1994 Alexandre Julliard
5 * Copyright 1997 Bertho A. Stultiens
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
24 #include "wine/port.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
);
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
;
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
)
80 if ((prev
= SelectObject( dev
->hdc
, brush
)))
82 ret
= PaintRgn( dev
->hdc
, rgn
);
83 SelectObject( dev
->hdc
, prev
);
88 BOOL
nulldrv_FrameRgn( PHYSDEV dev
, HRGN rgn
, HBRUSH brush
, INT width
, INT height
)
91 HRGN tmp
= CreateRectRgn( 0, 0, 0, 0 );
95 if (REGION_FrameRgn( tmp
, rgn
, width
, height
)) ret
= FillRgn( dev
->hdc
, tmp
, brush
);
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
);
111 BOOL
nulldrv_PolyBezier( PHYSDEV dev
, const POINT
*points
, DWORD count
)
117 if ((pts
= GDI_Bezier( points
, count
, &n
)))
119 ret
= Polyline( dev
->hdc
, pts
, n
);
120 HeapFree( GetProcessHeap(), 0, pts
);
125 BOOL
nulldrv_PolyBezierTo( PHYSDEV dev
, const POINT
*points
, DWORD count
)
128 POINT
*pts
= HeapAlloc( GetProcessHeap(), 0, sizeof(POINT
) * (count
+ 1) );
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
);
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
++)
151 case PT_LINETO
| PT_CLOSEFIGURE
:
155 if((i
+ 2 < count
) && (types
[i
+ 1] == PT_BEZIERTO
) &&
156 ((types
[i
+ 2] & ~PT_CLOSEFIGURE
) == PT_BEZIERTO
))
167 line_pts
= HeapAlloc( GetProcessHeap(), 0, space
* sizeof(POINT
) );
170 GetCurrentPositionEx( dev
->hdc
, &line_pts
[0] );
171 for (i
= 0; i
< count
; i
++)
176 if (num_pts
>= 2) Polyline( dev
->hdc
, line_pts
, num_pts
);
178 line_pts
[num_pts
++] = points
[i
];
181 case (PT_LINETO
| PT_CLOSEFIGURE
):
182 line_pts
[num_pts
++] = points
[i
];
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
;
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
);
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
);
213 BOOL
nulldrv_PolylineTo( PHYSDEV dev
, const POINT
*points
, INT count
)
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
);
229 /***********************************************************************
232 BOOL WINAPI
LineTo( HDC hdc
, INT x
, INT y
)
234 DC
* dc
= get_dc_ptr( hdc
);
237 if(!dc
) return FALSE
;
240 if(PATH_IsPathOpen(dc
->path
))
241 ret
= PATH_LineTo(dc
, x
, y
);
244 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pLineTo
);
245 ret
= physdev
->funcs
->pLineTo( physdev
, x
, y
);
251 release_dc_ptr( dc
);
256 /***********************************************************************
259 BOOL WINAPI
MoveToEx( HDC hdc
, INT x
, INT y
, LPPOINT pt
)
262 DC
* dc
= get_dc_ptr( hdc
);
264 if(!dc
) return FALSE
;
267 pt
->x
= dc
->CursPosX
;
268 pt
->y
= dc
->CursPosY
;
273 if(PATH_IsPathOpen(dc
->path
)) ret
= PATH_MoveTo(dc
);
276 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pMoveTo
);
277 ret
= physdev
->funcs
->pMoveTo( physdev
, x
, y
);
279 release_dc_ptr( dc
);
284 /***********************************************************************
287 BOOL WINAPI
Arc( HDC hdc
, INT left
, INT top
, INT right
,
288 INT bottom
, INT xstart
, INT ystart
,
292 DC
* dc
= get_dc_ptr( hdc
);
297 if(PATH_IsPathOpen(dc
->path
))
298 ret
= PATH_Arc(dc
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
,0);
301 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pArc
);
302 ret
= physdev
->funcs
->pArc( physdev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
);
304 release_dc_ptr( dc
);
309 /***********************************************************************
312 BOOL WINAPI
ArcTo( HDC hdc
,
314 INT right
, INT bottom
,
315 INT xstart
, INT ystart
,
318 double width
= fabs(right
-left
),
319 height
= fabs(bottom
-top
),
322 xcenter
= right
> left
? left
+xradius
: right
+xradius
,
323 ycenter
= bottom
> top
? top
+yradius
: bottom
+yradius
,
326 DC
* dc
= get_dc_ptr( hdc
);
327 if(!dc
) return FALSE
;
330 if(PATH_IsPathOpen(dc
->path
))
331 result
= PATH_Arc(dc
,left
,top
,right
,bottom
,xstart
,ystart
,xend
,yend
,-1);
334 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pArcTo
);
335 result
= physdev
->funcs
->pArcTo( physdev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
);
338 angle
= atan2(((yend
-ycenter
)/height
),
339 ((xend
-xcenter
)/width
));
340 dc
->CursPosX
= GDI_ROUND(xcenter
+(cos(angle
)*xradius
));
341 dc
->CursPosY
= GDI_ROUND(ycenter
+(sin(angle
)*yradius
));
343 release_dc_ptr( dc
);
348 /***********************************************************************
351 BOOL WINAPI
Pie( HDC hdc
, INT left
, INT top
,
352 INT right
, INT bottom
, INT xstart
, INT ystart
,
356 DC
* dc
= get_dc_ptr( hdc
);
357 if (!dc
) return FALSE
;
360 if(PATH_IsPathOpen(dc
->path
))
361 ret
= PATH_Arc(dc
,left
,top
,right
,bottom
,xstart
,ystart
,xend
,yend
,2);
364 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPie
);
365 ret
= physdev
->funcs
->pPie( physdev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
);
367 release_dc_ptr( dc
);
372 /***********************************************************************
375 BOOL WINAPI
Chord( HDC hdc
, INT left
, INT top
,
376 INT right
, INT bottom
, INT xstart
, INT ystart
,
380 DC
* dc
= get_dc_ptr( hdc
);
381 if (!dc
) return FALSE
;
384 if(PATH_IsPathOpen(dc
->path
))
385 ret
= PATH_Arc(dc
,left
,top
,right
,bottom
,xstart
,ystart
,xend
,yend
,1);
388 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pChord
);
389 ret
= physdev
->funcs
->pChord( physdev
, left
, top
, right
, bottom
, xstart
, ystart
, xend
, yend
);
391 release_dc_ptr( dc
);
396 /***********************************************************************
399 BOOL WINAPI
Ellipse( HDC hdc
, INT left
, INT top
,
400 INT right
, INT bottom
)
403 DC
* dc
= get_dc_ptr( hdc
);
404 if (!dc
) return FALSE
;
407 if(PATH_IsPathOpen(dc
->path
))
408 ret
= PATH_Ellipse(dc
,left
,top
,right
,bottom
);
411 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pEllipse
);
412 ret
= physdev
->funcs
->pEllipse( physdev
, left
, top
, right
, bottom
);
415 release_dc_ptr( dc
);
420 /***********************************************************************
421 * Rectangle (GDI32.@)
423 BOOL WINAPI
Rectangle( HDC hdc
, INT left
, INT top
,
424 INT right
, INT bottom
)
427 DC
* dc
= get_dc_ptr( hdc
);
432 if(PATH_IsPathOpen(dc
->path
))
433 ret
= PATH_Rectangle(dc
, left
, top
, right
, bottom
);
436 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pRectangle
);
437 ret
= physdev
->funcs
->pRectangle( physdev
, left
, top
, right
, bottom
);
439 release_dc_ptr( dc
);
445 /***********************************************************************
446 * RoundRect (GDI32.@)
448 BOOL WINAPI
RoundRect( HDC hdc
, INT left
, INT top
, INT right
,
449 INT bottom
, INT ell_width
, INT ell_height
)
452 DC
*dc
= get_dc_ptr( hdc
);
457 if(PATH_IsPathOpen(dc
->path
))
458 ret
= PATH_RoundRect(dc
,left
,top
,right
,bottom
,ell_width
,ell_height
);
461 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pRoundRect
);
462 ret
= physdev
->funcs
->pRoundRect( physdev
, left
, top
, right
, bottom
, ell_width
, ell_height
);
464 release_dc_ptr( dc
);
469 /***********************************************************************
472 COLORREF WINAPI
SetPixel( HDC hdc
, INT x
, INT y
, COLORREF color
)
475 DC
* dc
= get_dc_ptr( hdc
);
479 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetPixel
);
481 ret
= physdev
->funcs
->pSetPixel( physdev
, x
, y
, color
);
482 release_dc_ptr( dc
);
487 /***********************************************************************
488 * SetPixelV (GDI32.@)
490 BOOL WINAPI
SetPixelV( HDC hdc
, INT x
, INT y
, COLORREF color
)
493 DC
* dc
= get_dc_ptr( hdc
);
497 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetPixel
);
499 physdev
->funcs
->pSetPixel( physdev
, x
, y
, color
);
501 release_dc_ptr( dc
);
506 /***********************************************************************
509 COLORREF WINAPI
GetPixel( HDC hdc
, INT x
, INT y
)
511 COLORREF ret
= CLR_INVALID
;
512 DC
* dc
= get_dc_ptr( hdc
);
517 /* FIXME: should this be in the graphics driver? */
518 if (PtVisible( hdc
, x
, y
))
520 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pGetPixel
);
521 ret
= physdev
->funcs
->pGetPixel( physdev
, x
, y
);
523 release_dc_ptr( dc
);
529 /******************************************************************************
530 * ChoosePixelFormat [GDI32.@]
531 * Matches a pixel format to given format
534 * hdc [I] Device context to search for best pixel match
535 * ppfd [I] Pixel format for which a match is sought
538 * Success: Pixel format index closest to given format
541 INT WINAPI
ChoosePixelFormat( HDC hdc
, const PIXELFORMATDESCRIPTOR
* ppfd
)
544 DC
* dc
= get_dc_ptr( hdc
);
546 TRACE("(%p,%p)\n",hdc
,ppfd
);
550 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pChoosePixelFormat
);
551 ret
= physdev
->funcs
->pChoosePixelFormat( physdev
, ppfd
);
552 release_dc_ptr( dc
);
558 /******************************************************************************
559 * SetPixelFormat [GDI32.@]
560 * Sets pixel format of device context
563 * hdc [I] Device context to search for best pixel match
564 * iPixelFormat [I] Pixel format index
565 * ppfd [I] Pixel format for which a match is sought
571 BOOL WINAPI
SetPixelFormat( HDC hdc
, INT iPixelFormat
,
572 const PIXELFORMATDESCRIPTOR
*ppfd
)
575 DC
* dc
= get_dc_ptr( hdc
);
577 TRACE("(%p,%d,%p)\n",hdc
,iPixelFormat
,ppfd
);
581 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSetPixelFormat
);
583 bRet
= physdev
->funcs
->pSetPixelFormat( physdev
, iPixelFormat
, ppfd
);
584 release_dc_ptr( dc
);
590 /******************************************************************************
591 * GetPixelFormat [GDI32.@]
592 * Gets index of pixel format of DC
595 * hdc [I] Device context whose pixel format index is sought
598 * Success: Currently selected pixel format
601 INT WINAPI
GetPixelFormat( HDC hdc
)
604 DC
* dc
= get_dc_ptr( hdc
);
610 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pGetPixelFormat
);
612 ret
= physdev
->funcs
->pGetPixelFormat( physdev
);
613 release_dc_ptr( dc
);
619 /******************************************************************************
620 * DescribePixelFormat [GDI32.@]
621 * Gets info about pixel format from DC
624 * hdc [I] Device context
625 * iPixelFormat [I] Pixel format selector
626 * nBytes [I] Size of buffer
627 * ppfd [O] Pointer to structure to receive pixel format data
630 * Success: Maximum pixel format index of the device context
633 INT WINAPI
DescribePixelFormat( HDC hdc
, INT iPixelFormat
, UINT nBytes
,
634 LPPIXELFORMATDESCRIPTOR ppfd
)
637 DC
* dc
= get_dc_ptr( hdc
);
639 TRACE("(%p,%d,%d,%p): stub\n",hdc
,iPixelFormat
,nBytes
,ppfd
);
643 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pDescribePixelFormat
);
645 ret
= physdev
->funcs
->pDescribePixelFormat( physdev
, iPixelFormat
, nBytes
, ppfd
);
646 release_dc_ptr( dc
);
652 /******************************************************************************
653 * SwapBuffers [GDI32.@]
654 * Exchanges front and back buffers of window
657 * hdc [I] Device context whose buffers get swapped
663 BOOL WINAPI
SwapBuffers( HDC hdc
)
666 DC
* dc
= get_dc_ptr( hdc
);
672 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pSwapBuffers
);
674 bRet
= physdev
->funcs
->pSwapBuffers( physdev
);
675 release_dc_ptr( dc
);
681 /***********************************************************************
684 BOOL WINAPI
PaintRgn( HDC hdc
, HRGN hrgn
)
687 DC
* dc
= get_dc_ptr( hdc
);
691 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPaintRgn
);
693 ret
= physdev
->funcs
->pPaintRgn( physdev
, hrgn
);
694 release_dc_ptr( dc
);
700 /***********************************************************************
703 BOOL WINAPI
FillRgn( HDC hdc
, HRGN hrgn
, HBRUSH hbrush
)
706 DC
* dc
= get_dc_ptr( hdc
);
710 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pFillRgn
);
712 retval
= physdev
->funcs
->pFillRgn( physdev
, hrgn
, hbrush
);
713 release_dc_ptr( dc
);
719 /***********************************************************************
722 BOOL WINAPI
FrameRgn( HDC hdc
, HRGN hrgn
, HBRUSH hbrush
,
723 INT nWidth
, INT nHeight
)
726 DC
*dc
= get_dc_ptr( hdc
);
730 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pFrameRgn
);
732 ret
= physdev
->funcs
->pFrameRgn( physdev
, hrgn
, hbrush
, nWidth
, nHeight
);
733 release_dc_ptr( dc
);
739 /***********************************************************************
740 * InvertRgn (GDI32.@)
742 BOOL WINAPI
InvertRgn( HDC hdc
, HRGN hrgn
)
745 DC
*dc
= get_dc_ptr( hdc
);
749 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pInvertRgn
);
751 ret
= physdev
->funcs
->pInvertRgn( physdev
, hrgn
);
752 release_dc_ptr( dc
);
758 /**********************************************************************
761 BOOL WINAPI
Polyline( HDC hdc
, const POINT
* pt
, INT count
)
764 DC
* dc
= get_dc_ptr( hdc
);
769 if (PATH_IsPathOpen(dc
->path
)) ret
= PATH_Polyline(dc
, pt
, count
);
772 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyline
);
773 ret
= physdev
->funcs
->pPolyline( physdev
, pt
, count
);
775 release_dc_ptr( dc
);
780 /**********************************************************************
781 * PolylineTo (GDI32.@)
783 BOOL WINAPI
PolylineTo( HDC hdc
, const POINT
* pt
, DWORD cCount
)
785 DC
* dc
= get_dc_ptr( hdc
);
788 if(!dc
) return FALSE
;
791 if(PATH_IsPathOpen(dc
->path
)) ret
= PATH_PolylineTo(dc
, pt
, cCount
);
794 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolylineTo
);
795 ret
= physdev
->funcs
->pPolylineTo( physdev
, pt
, cCount
);
799 dc
->CursPosX
= pt
[cCount
-1].x
;
800 dc
->CursPosY
= pt
[cCount
-1].y
;
802 release_dc_ptr( dc
);
807 /**********************************************************************
810 BOOL WINAPI
Polygon( HDC hdc
, const POINT
* pt
, INT count
)
813 DC
* dc
= get_dc_ptr( hdc
);
818 if (PATH_IsPathOpen(dc
->path
)) ret
= PATH_Polygon(dc
, pt
, count
);
821 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolygon
);
822 ret
= physdev
->funcs
->pPolygon( physdev
, pt
, count
);
824 release_dc_ptr( dc
);
830 /**********************************************************************
831 * PolyPolygon (GDI32.@)
833 BOOL WINAPI
PolyPolygon( HDC hdc
, const POINT
* pt
, const INT
* counts
,
837 DC
* dc
= get_dc_ptr( hdc
);
842 if (PATH_IsPathOpen(dc
->path
)) ret
= PATH_PolyPolygon(dc
, pt
, counts
, polygons
);
845 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyPolygon
);
846 ret
= physdev
->funcs
->pPolyPolygon( physdev
, pt
, counts
, polygons
);
848 release_dc_ptr( dc
);
853 /**********************************************************************
854 * PolyPolyline (GDI32.@)
856 BOOL WINAPI
PolyPolyline( HDC hdc
, const POINT
* pt
, const DWORD
* counts
,
860 DC
* dc
= get_dc_ptr( hdc
);
865 if (PATH_IsPathOpen(dc
->path
)) ret
= PATH_PolyPolyline(dc
, pt
, counts
, polylines
);
868 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyPolyline
);
869 ret
= physdev
->funcs
->pPolyPolyline( physdev
, pt
, counts
, polylines
);
871 release_dc_ptr( dc
);
876 /**********************************************************************
877 * ExtFloodFill (GDI32.@)
879 BOOL WINAPI
ExtFloodFill( HDC hdc
, INT x
, INT y
, COLORREF color
,
883 DC
* dc
= get_dc_ptr( hdc
);
887 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pExtFloodFill
);
890 ret
= physdev
->funcs
->pExtFloodFill( physdev
, x
, y
, color
, fillType
);
891 release_dc_ptr( dc
);
897 /**********************************************************************
898 * FloodFill (GDI32.@)
900 BOOL WINAPI
FloodFill( HDC hdc
, INT x
, INT y
, COLORREF color
)
902 return ExtFloodFill( hdc
, x
, y
, color
, FLOODFILLBORDER
);
906 /******************************************************************************
907 * PolyBezier [GDI32.@]
908 * Draws one or more Bezier curves
911 * hDc [I] Handle to device context
912 * lppt [I] Pointer to endpoints and control points
913 * cPoints [I] Count of endpoints and control points
919 BOOL WINAPI
PolyBezier( HDC hdc
, const POINT
* lppt
, DWORD cPoints
)
924 /* cPoints must be 3 * n + 1 (where n>=1) */
925 if (cPoints
== 1 || (cPoints
% 3) != 1) return FALSE
;
927 dc
= get_dc_ptr( hdc
);
928 if(!dc
) return FALSE
;
931 if(PATH_IsPathOpen(dc
->path
)) ret
= PATH_PolyBezier(dc
, lppt
, cPoints
);
934 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyBezier
);
935 ret
= physdev
->funcs
->pPolyBezier( physdev
, lppt
, cPoints
);
937 release_dc_ptr( dc
);
941 /******************************************************************************
942 * PolyBezierTo [GDI32.@]
943 * Draws one or more Bezier curves
946 * hDc [I] Handle to device context
947 * lppt [I] Pointer to endpoints and control points
948 * cPoints [I] Count of endpoints and control points
954 BOOL WINAPI
PolyBezierTo( HDC hdc
, const POINT
* lppt
, DWORD cPoints
)
959 /* cbPoints must be 3 * n (where n>=1) */
960 if (!cPoints
|| (cPoints
% 3) != 0) return FALSE
;
962 dc
= get_dc_ptr( hdc
);
963 if(!dc
) return FALSE
;
966 if(PATH_IsPathOpen(dc
->path
)) ret
= PATH_PolyBezierTo(dc
, lppt
, cPoints
);
969 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyBezierTo
);
970 ret
= physdev
->funcs
->pPolyBezierTo( physdev
, lppt
, cPoints
);
973 dc
->CursPosX
= lppt
[cPoints
-1].x
;
974 dc
->CursPosY
= lppt
[cPoints
-1].y
;
976 release_dc_ptr( dc
);
980 /***********************************************************************
983 BOOL WINAPI
AngleArc(HDC hdc
, INT x
, INT y
, DWORD dwRadius
, FLOAT eStartAngle
, FLOAT eSweepAngle
)
985 INT x1
,y1
,x2
,y2
, arcdir
;
989 if( (signed int)dwRadius
< 0 )
992 dc
= get_dc_ptr( hdc
);
993 if(!dc
) return FALSE
;
995 /* Calculate the end point */
996 x2
= GDI_ROUND( x
+ cos((eStartAngle
+eSweepAngle
)*M_PI
/180) * dwRadius
);
997 y2
= GDI_ROUND( y
- sin((eStartAngle
+eSweepAngle
)*M_PI
/180) * dwRadius
);
1000 if(!PATH_IsPathOpen(dc
->path
))
1002 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pAngleArc
);
1003 result
= physdev
->funcs
->pAngleArc( physdev
, x
, y
, dwRadius
, eStartAngle
, eSweepAngle
);
1005 else { /* do it using ArcTo */
1006 x1
= GDI_ROUND( x
+ cos(eStartAngle
*M_PI
/180) * dwRadius
);
1007 y1
= GDI_ROUND( y
- sin(eStartAngle
*M_PI
/180) * dwRadius
);
1009 arcdir
= SetArcDirection( hdc
, eSweepAngle
>= 0 ? AD_COUNTERCLOCKWISE
: AD_CLOCKWISE
);
1010 result
= ArcTo( hdc
, x
-dwRadius
, y
-dwRadius
, x
+dwRadius
, y
+dwRadius
,
1012 SetArcDirection( hdc
, arcdir
);
1018 release_dc_ptr( dc
);
1022 /***********************************************************************
1023 * PolyDraw (GDI32.@)
1025 BOOL WINAPI
PolyDraw(HDC hdc
, const POINT
*lppt
, const BYTE
*lpbTypes
,
1028 DC
*dc
= get_dc_ptr( hdc
);
1029 BOOL result
= FALSE
;
1031 if(!dc
) return FALSE
;
1034 if( PATH_IsPathOpen( dc
->path
) ) result
= PATH_PolyDraw(dc
, lppt
, lpbTypes
, cCount
);
1037 PHYSDEV physdev
= GET_DC_PHYSDEV( dc
, pPolyDraw
);
1038 result
= physdev
->funcs
->pPolyDraw( physdev
, lppt
, lpbTypes
, cCount
);
1040 release_dc_ptr( dc
);
1045 /**********************************************************************
1048 BOOL WINAPI
LineDDA(INT nXStart
, INT nYStart
, INT nXEnd
, INT nYEnd
,
1049 LINEDDAPROC callback
, LPARAM lParam
)
1051 INT xadd
= 1, yadd
= 1;
1054 INT dx
= nXEnd
- nXStart
;
1055 INT dy
= nYEnd
- nYStart
;
1067 if (dx
> dy
) /* line is "more horizontal" */
1069 err
= 2*dy
- dx
; erradd
= 2*dy
- 2*dx
;
1070 for(cnt
= 0;cnt
< dx
; cnt
++)
1072 callback(nXStart
,nYStart
,lParam
);
1082 else /* line is "more vertical" */
1084 err
= 2*dx
- dy
; erradd
= 2*dx
- 2*dy
;
1085 for(cnt
= 0;cnt
< dy
; cnt
++)
1087 callback(nXStart
,nYStart
,lParam
);
1101 /******************************************************************
1103 * *Very* simple bezier drawing code,
1105 * It uses a recursive algorithm to divide the curve in a series
1106 * of straight line segments. Not ideal but sufficient for me.
1107 * If you are in need for something better look for some incremental
1110 * 7 July 1998 Rein Klazes
1114 * some macro definitions for bezier drawing
1116 * to avoid truncation errors the coordinates are
1117 * shifted upwards. When used in drawing they are
1118 * shifted down again, including correct rounding
1119 * and avoiding floating point arithmetic
1120 * 4 bits should allow 27 bits coordinates which I saw
1121 * somewhere in the win32 doc's
1125 #define BEZIERSHIFTBITS 4
1126 #define BEZIERSHIFTUP(x) ((x)<<BEZIERSHIFTBITS)
1127 #define BEZIERPIXEL BEZIERSHIFTUP(1)
1128 #define BEZIERSHIFTDOWN(x) (((x)+(1<<(BEZIERSHIFTBITS-1)))>>BEZIERSHIFTBITS)
1129 /* maximum depth of recursion */
1130 #define BEZIERMAXDEPTH 8
1132 /* size of array to store points on */
1133 /* enough for one curve */
1134 #define BEZIER_INITBUFSIZE (150)
1136 /* calculate Bezier average, in this case the middle
1137 * correctly rounded...
1140 #define BEZIERMIDDLE(Mid, P1, P2) \
1141 (Mid).x=((P1).x+(P2).x + 1)/2;\
1142 (Mid).y=((P1).y+(P2).y + 1)/2;
1144 /**********************************************************
1145 * BezierCheck helper function to check
1146 * that recursion can be terminated
1147 * Points[0] and Points[3] are begin and endpoint
1148 * Points[1] and Points[2] are control points
1149 * level is the recursion depth
1150 * returns true if the recursion can be terminated
1152 static BOOL
BezierCheck( int level
, POINT
*Points
)
1155 dx
=Points
[3].x
-Points
[0].x
;
1156 dy
=Points
[3].y
-Points
[0].y
;
1157 if(abs(dy
)<=abs(dx
)){/* shallow line */
1158 /* check that control points are between begin and end */
1159 if(Points
[1].x
< Points
[0].x
){
1160 if(Points
[1].x
< Points
[3].x
)
1163 if(Points
[1].x
> Points
[3].x
)
1165 if(Points
[2].x
< Points
[0].x
){
1166 if(Points
[2].x
< Points
[3].x
)
1169 if(Points
[2].x
> Points
[3].x
)
1171 dx
=BEZIERSHIFTDOWN(dx
);
1172 if(!dx
) return TRUE
;
1173 if(abs(Points
[1].y
-Points
[0].y
-(dy
/dx
)*
1174 BEZIERSHIFTDOWN(Points
[1].x
-Points
[0].x
)) > BEZIERPIXEL
||
1175 abs(Points
[2].y
-Points
[0].y
-(dy
/dx
)*
1176 BEZIERSHIFTDOWN(Points
[2].x
-Points
[0].x
)) > BEZIERPIXEL
)
1180 }else{ /* steep line */
1181 /* check that control points are between begin and end */
1182 if(Points
[1].y
< Points
[0].y
){
1183 if(Points
[1].y
< Points
[3].y
)
1186 if(Points
[1].y
> Points
[3].y
)
1188 if(Points
[2].y
< Points
[0].y
){
1189 if(Points
[2].y
< Points
[3].y
)
1192 if(Points
[2].y
> Points
[3].y
)
1194 dy
=BEZIERSHIFTDOWN(dy
);
1195 if(!dy
) return TRUE
;
1196 if(abs(Points
[1].x
-Points
[0].x
-(dx
/dy
)*
1197 BEZIERSHIFTDOWN(Points
[1].y
-Points
[0].y
)) > BEZIERPIXEL
||
1198 abs(Points
[2].x
-Points
[0].x
-(dx
/dy
)*
1199 BEZIERSHIFTDOWN(Points
[2].y
-Points
[0].y
)) > BEZIERPIXEL
)
1206 /* Helper for GDI_Bezier.
1207 * Just handles one Bezier, so Points should point to four POINTs
1209 static void GDI_InternalBezier( POINT
*Points
, POINT
**PtsOut
, INT
*dwOut
,
1210 INT
*nPtsOut
, INT level
)
1212 if(*nPtsOut
== *dwOut
) {
1214 *PtsOut
= HeapReAlloc( GetProcessHeap(), 0, *PtsOut
,
1215 *dwOut
* sizeof(POINT
) );
1218 if(!level
|| BezierCheck(level
, Points
)) {
1220 (*PtsOut
)[0].x
= BEZIERSHIFTDOWN(Points
[0].x
);
1221 (*PtsOut
)[0].y
= BEZIERSHIFTDOWN(Points
[0].y
);
1224 (*PtsOut
)[*nPtsOut
].x
= BEZIERSHIFTDOWN(Points
[3].x
);
1225 (*PtsOut
)[*nPtsOut
].y
= BEZIERSHIFTDOWN(Points
[3].y
);
1228 POINT Points2
[4]; /* for the second recursive call */
1229 Points2
[3]=Points
[3];
1230 BEZIERMIDDLE(Points2
[2], Points
[2], Points
[3]);
1231 BEZIERMIDDLE(Points2
[0], Points
[1], Points
[2]);
1232 BEZIERMIDDLE(Points2
[1],Points2
[0],Points2
[2]);
1234 BEZIERMIDDLE(Points
[1], Points
[0], Points
[1]);
1235 BEZIERMIDDLE(Points
[2], Points
[1], Points2
[0]);
1236 BEZIERMIDDLE(Points
[3], Points
[2], Points2
[1]);
1238 Points2
[0]=Points
[3];
1240 /* do the two halves */
1241 GDI_InternalBezier(Points
, PtsOut
, dwOut
, nPtsOut
, level
-1);
1242 GDI_InternalBezier(Points2
, PtsOut
, dwOut
, nPtsOut
, level
-1);
1248 /***********************************************************************
1249 * GDI_Bezier [INTERNAL]
1250 * Calculate line segments that approximate -what microsoft calls- a bezier
1252 * The routine recursively divides the curve in two parts until a straight
1257 * Points [I] Ptr to count POINTs which are the end and control points
1258 * of the set of Bezier curves to flatten.
1259 * count [I] Number of Points. Must be 3n+1.
1260 * nPtsOut [O] Will contain no of points that have been produced (i.e. no. of
1265 * Ptr to an array of POINTs that contain the lines that approximate the
1266 * Beziers. The array is allocated on the process heap and it is the caller's
1267 * responsibility to HeapFree it. [this is not a particularly nice interface
1268 * but since we can't know in advance how many points we will generate, the
1269 * alternative would be to call the function twice, once to determine the size
1270 * and a second time to do the work - I decided this was too much of a pain].
1272 POINT
*GDI_Bezier( const POINT
*Points
, INT count
, INT
*nPtsOut
)
1275 INT Bezier
, dwOut
= BEZIER_INITBUFSIZE
, i
;
1277 if (count
== 1 || (count
- 1) % 3 != 0) {
1278 ERR("Invalid no. of points %d\n", count
);
1282 out
= HeapAlloc( GetProcessHeap(), 0, dwOut
* sizeof(POINT
));
1283 for(Bezier
= 0; Bezier
< (count
-1)/3; Bezier
++) {
1285 memcpy(ptBuf
, Points
+ Bezier
* 3, sizeof(POINT
) * 4);
1286 for(i
= 0; i
< 4; i
++) {
1287 ptBuf
[i
].x
= BEZIERSHIFTUP(ptBuf
[i
].x
);
1288 ptBuf
[i
].y
= BEZIERSHIFTUP(ptBuf
[i
].y
);
1290 GDI_InternalBezier( ptBuf
, &out
, &dwOut
, nPtsOut
, BEZIERMAXDEPTH
);
1292 TRACE("Produced %d points\n", *nPtsOut
);
1296 /******************************************************************************
1297 * GdiGradientFill (GDI32.@)
1299 * FIXME: we don't support the Alpha channel properly
1301 BOOL WINAPI
GdiGradientFill( HDC hdc
, TRIVERTEX
*vert_array
, ULONG nvert
,
1302 void * grad_array
, ULONG ngrad
, ULONG mode
)
1306 TRACE("vert_array:%p nvert:%d grad_array:%p ngrad:%d\n",
1307 vert_array
, nvert
, grad_array
, ngrad
);
1311 case GRADIENT_FILL_RECT_H
:
1312 for(i
= 0; i
< ngrad
; i
++)
1314 GRADIENT_RECT
*rect
= ((GRADIENT_RECT
*)grad_array
) + i
;
1315 TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
1316 TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
1317 int y1
= v1
->y
< v2
->y
? v1
->y
: v2
->y
;
1318 int y2
= v2
->y
> v1
->y
? v2
->y
: v1
->y
;
1327 for (x
= 0; x
< dx
; x
++)
1332 hPen
= CreatePen( PS_SOLID
, 1, RGB(
1333 (v1
->Red
* (dx
- x
) + v2
->Red
* x
) / dx
>> 8,
1334 (v1
->Green
* (dx
- x
) + v2
->Green
* x
) / dx
>> 8,
1335 (v1
->Blue
* (dx
- x
) + v2
->Blue
* x
) / dx
>> 8));
1336 hOldPen
= SelectObject( hdc
, hPen
);
1337 pts
[0].x
= v1
->x
+ x
;
1339 pts
[1].x
= v1
->x
+ x
;
1341 Polyline( hdc
, &pts
[0], 2 );
1342 DeleteObject( SelectObject(hdc
, hOldPen
) );
1346 case GRADIENT_FILL_RECT_V
:
1347 for(i
= 0; i
< ngrad
; i
++)
1349 GRADIENT_RECT
*rect
= ((GRADIENT_RECT
*)grad_array
) + i
;
1350 TRIVERTEX
*v1
= vert_array
+ rect
->UpperLeft
;
1351 TRIVERTEX
*v2
= vert_array
+ rect
->LowerRight
;
1352 int x1
= v1
->x
< v2
->x
? v1
->x
: v2
->x
;
1353 int x2
= v2
->x
> v1
->x
? v2
->x
: v1
->x
;
1362 for (y
= 0; y
< dy
; y
++)
1367 hPen
= CreatePen( PS_SOLID
, 1, RGB(
1368 (v1
->Red
* (dy
- y
) + v2
->Red
* y
) / dy
>> 8,
1369 (v1
->Green
* (dy
- y
) + v2
->Green
* y
) / dy
>> 8,
1370 (v1
->Blue
* (dy
- y
) + v2
->Blue
* y
) / dy
>> 8));
1371 hOldPen
= SelectObject( hdc
, hPen
);
1373 pts
[0].y
= v1
->y
+ y
;
1375 pts
[1].y
= v1
->y
+ y
;
1376 Polyline( hdc
, &pts
[0], 2 );
1377 DeleteObject( SelectObject(hdc
, hOldPen
) );
1381 case GRADIENT_FILL_TRIANGLE
:
1382 for (i
= 0; i
< ngrad
; i
++)
1384 GRADIENT_TRIANGLE
*tri
= ((GRADIENT_TRIANGLE
*)grad_array
) + i
;
1385 TRIVERTEX
*v1
= vert_array
+ tri
->Vertex1
;
1386 TRIVERTEX
*v2
= vert_array
+ tri
->Vertex2
;
1387 TRIVERTEX
*v3
= vert_array
+ tri
->Vertex3
;
1391 { TRIVERTEX
*t
= v1
; v1
= v2
; v2
= t
; }
1394 TRIVERTEX
*t
= v2
; v2
= v3
; v3
= t
;
1396 { t
= v1
; v1
= v2
; v2
= t
; }
1398 /* v1->y <= v2->y <= v3->y */
1401 for (y
= 0; y
< dy
; y
++)
1403 /* v1->y <= y < v3->y */
1404 TRIVERTEX
*v
= y
< (v2
->y
- v1
->y
) ? v1
: v3
;
1405 /* (v->y <= y < v2->y) || (v2->y <= y < v->y) */
1406 int dy2
= v2
->y
- v
->y
;
1407 int y2
= y
+ v1
->y
- v
->y
;
1409 int x1
= (v3
->x
* y
+ v1
->x
* (dy
- y
)) / dy
;
1410 int x2
= (v2
->x
* y2
+ v
-> x
* (dy2
- y2
)) / dy2
;
1411 int r1
= (v3
->Red
* y
+ v1
->Red
* (dy
- y
)) / dy
;
1412 int r2
= (v2
->Red
* y2
+ v
-> Red
* (dy2
- y2
)) / dy2
;
1413 int g1
= (v3
->Green
* y
+ v1
->Green
* (dy
- y
)) / dy
;
1414 int g2
= (v2
->Green
* y2
+ v
-> Green
* (dy2
- y2
)) / dy2
;
1415 int b1
= (v3
->Blue
* y
+ v1
->Blue
* (dy
- y
)) / dy
;
1416 int b2
= (v2
->Blue
* y2
+ v
-> Blue
* (dy2
- y2
)) / dy2
;
1422 for (x
= 0; x
< dx
; x
++)
1423 SetPixel (hdc
, x
+ x1
, y
+ v1
->y
, RGB(
1424 (r1
* (dx
- x
) + r2
* x
) / dx
>> 8,
1425 (g1
* (dx
- x
) + g2
* x
) / dx
>> 8,
1426 (b1
* (dx
- x
) + b2
* x
) / dx
>> 8));
1431 for (x
= 0; x
< dx
; x
++)
1432 SetPixel (hdc
, x
+ x2
, y
+ v1
->y
, RGB(
1433 (r2
* (dx
- x
) + r1
* x
) / dx
>> 8,
1434 (g2
* (dx
- x
) + g1
* x
) / dx
>> 8,
1435 (b2
* (dx
- x
) + b1
* x
) / dx
>> 8));
1447 /******************************************************************************
1448 * GdiDrawStream (GDI32.@)
1451 BOOL WINAPI
GdiDrawStream( HDC hdc
, ULONG in
, void * pvin
)
1453 FIXME("stub: %p, %d, %p\n", hdc
, in
, pvin
);