2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 * a couple macros to fill a single pixel or a line
28 #define PUTPIXEL(x,y,BrushInst) \
29 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
31 &BrushInst.BrushObject, \
34 ROP2_TO_MIX(dc->Dc_Attr.jROP2));
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
39 &BrushInst.BrushObject, \
42 ROP2_TO_MIX(dc->Dc_Attr.jROP2));
50 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
51 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
52 BOOL ret
= FALSE
; // default to failure
56 ASSERT(dc
); // caller's responsibility to pass a valid dc
58 if ( NULL
== UnsafePoints
|| Count
< 2 )
60 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
64 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
65 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
68 /* Convert to screen coordinates */
69 IntLPtoDP(dc
, UnsafePoints
, Count
);
70 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
72 UnsafePoints
[CurrentPoint
].x
+= dc
->w
.DCOrgX
;
73 UnsafePoints
[CurrentPoint
].y
+= dc
->w
.DCOrgY
;
76 if (PATH_IsPathOpen(dc
->w
.path
))
77 ret
= PATH_Polygon(dc
, UnsafePoints
, Count
);
80 DestRect
.left
= UnsafePoints
[0].x
;
81 DestRect
.right
= UnsafePoints
[0].x
;
82 DestRect
.top
= UnsafePoints
[0].y
;
83 DestRect
.bottom
= UnsafePoints
[0].y
;
85 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
87 DestRect
.left
= min(DestRect
.left
, UnsafePoints
[CurrentPoint
].x
);
88 DestRect
.right
= max(DestRect
.right
, UnsafePoints
[CurrentPoint
].x
);
89 DestRect
.top
= min(DestRect
.top
, UnsafePoints
[CurrentPoint
].y
);
90 DestRect
.bottom
= max(DestRect
.bottom
, UnsafePoints
[CurrentPoint
].y
);
93 /* Now fill the polygon with the current brush. */
94 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->Dc_Attr
.hbrush
);
95 if (FillBrushObj
&& !(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
97 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
98 ret
= FillPolygon ( dc
, BitmapObj
, &FillBrushInst
.BrushObject
, ROP2_TO_MIX(dc
->Dc_Attr
.jROP2
), UnsafePoints
, Count
, DestRect
);
100 BRUSHOBJ_UnlockBrush(FillBrushObj
);
102 /* get BRUSHOBJ from current pen. */
103 PenBrushObj
= PENOBJ_LockPen(dc
->Dc_Attr
.hpen
);
104 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
105 if (PenBrushObj
&& !(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
107 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
112 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
113 // UnsafePoints[0].x, UnsafePoints[0].y,
114 // UnsafePoints[1].x, UnsafePoints[1].y );
116 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
118 &PenBrushInst
.BrushObject
,
119 UnsafePoints
[0].x
, /* From */
121 UnsafePoints
[1].x
, /* To */
124 ROP2_TO_MIX(dc
->Dc_Attr
.jROP2
)); /* MIX */
129 PENOBJ_UnlockPen(PenBrushObj
);
131 BITMAPOBJ_UnlockBitmap(BitmapObj
);
137 IntGdiPolyPolygon(DC
*dc
,
144 if(!IntGdiPolygon ( dc
, Points
, *PolyCounts
)) return FALSE
;
145 Points
+=*PolyCounts
++;
150 /******************************************************************************/
159 * This function uses optimized Bresenham's ellipse algorithm. It draws
160 * four lines of the ellipse in one pass.
163 * Make it look like a Windows ellipse.
177 int NewA
, NewB
, NewC
, NewD
;
179 int CenterX
, CenterY
;
180 int RadiusX
, RadiusY
;
182 PGDIBRUSHOBJ FillBrush
, PenBrush
;
183 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
184 BITMAPOBJ
*BitmapObj
;
187 BOOL ret
= TRUE
, Cond1
, Cond2
;
190 * Check the parameters.
193 if (nRightRect
<= nLeftRect
|| nBottomRect
<= nTopRect
)
195 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
200 * Get pointers to all necessary GDI objects.
206 SetLastWin32Error(ERROR_INVALID_HANDLE
);
212 /* Yes, Windows really returns TRUE in this case */
216 FillBrush
= BRUSHOBJ_LockBrush(dc
->Dc_Attr
.hbrush
);
217 if (NULL
== FillBrush
)
220 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
224 PenBrush
= PENOBJ_LockPen(dc
->Dc_Attr
.hpen
);
225 if (NULL
== PenBrush
)
227 BRUSHOBJ_UnlockBrush(FillBrush
);
229 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
233 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
234 if (NULL
== BitmapObj
)
236 BRUSHOBJ_UnlockBrush(FillBrush
);
237 PENOBJ_UnlockPen(PenBrush
);
239 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
243 IntGdiInitBrushInstance(&FillBrushInst
, FillBrush
, dc
->XlateBrush
);
244 IntGdiInitBrushInstance(&PenBrushInst
, PenBrush
, dc
->XlatePen
);
246 RectBounds
.left
= nLeftRect
;
247 RectBounds
.right
= nRightRect
;
248 RectBounds
.top
= nTopRect
;
249 RectBounds
.bottom
= nBottomRect
;
251 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
253 RectBounds
.left
+= dc
->w
.DCOrgX
;
254 RectBounds
.right
+= dc
->w
.DCOrgX
;
255 RectBounds
.top
+= dc
->w
.DCOrgY
;
256 RectBounds
.bottom
+= dc
->w
.DCOrgY
;
258 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) >> 1, 1);
259 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) >> 1, 1);
260 CenterX
= RectBounds
.left
+ RadiusX
;
261 CenterY
= RectBounds
.top
+ RadiusY
;
263 if (RadiusX
> RadiusY
)
279 NewB
= (iy
+ 32) >> 6;
281 NewD
= (NewB
* ny
) / nx
;
291 NewA
= (ix
+ 32) >> 6;
292 NewB
= (iy
+ 32) >> 6;
293 NewC
= (NewA
* ny
) / nx
;
294 NewD
= (NewB
* ny
) / nx
;
296 if (RadiusX
> RadiusY
)
298 Temp
= A
; A
= C
; C
= Temp
;
299 Temp
= B
; B
= D
; D
= Temp
;
300 Cond1
= ((C
!= NewA
) || (B
!= NewD
)) && (NewC
<= NewD
);
301 Cond2
= ((D
!= NewB
) || (A
!= NewC
)) && (NewC
<= B
);
305 Cond1
= ((C
!= NewC
) || (B
!= NewB
)) && (NewA
<= NewB
);
306 Cond2
= ((D
!= NewD
) || (A
!= NewA
)) && (NewA
<= B
);
310 * Draw the lines going from inner to outer (+ mirrored).
313 if ((A
> da
) && (A
< db
))
315 PUTLINE(CenterX
- D
, CenterY
+ A
, CenterX
+ D
, CenterY
+ A
, FillBrushInst
);
318 PUTLINE(CenterX
- D
, CenterY
- A
, CenterX
+ D
, CenterY
- A
, FillBrushInst
);
324 * Draw the lines going from outer to inner (+ mirrored).
327 if ((B
< db
) && (B
> da
))
329 PUTLINE(CenterX
- C
, CenterY
+ B
, CenterX
+ C
, CenterY
+ B
, FillBrushInst
);
330 PUTLINE(CenterX
- C
, CenterY
- B
, CenterX
+ C
, CenterY
- B
, FillBrushInst
);
335 * Draw the pixels on the margin.
340 PUTPIXEL(CenterX
+ C
, CenterY
+ B
, PenBrushInst
);
342 PUTPIXEL(CenterX
- C
, CenterY
+ B
, PenBrushInst
);
345 PUTPIXEL(CenterX
+ C
, CenterY
- B
, PenBrushInst
);
347 PUTPIXEL(CenterX
- C
, CenterY
- B
, PenBrushInst
);
353 PUTPIXEL(CenterX
+ D
, CenterY
+ A
, PenBrushInst
);
355 PUTPIXEL(CenterX
- D
, CenterY
+ A
, PenBrushInst
);
358 PUTPIXEL(CenterX
+ D
, CenterY
- A
, PenBrushInst
);
360 PUTPIXEL(CenterX
- D
, CenterY
- A
, PenBrushInst
);
365 BITMAPOBJ_UnlockBitmap(BitmapObj
);
366 BRUSHOBJ_UnlockBrush(FillBrush
);
367 PENOBJ_UnlockPen(PenBrush
);
373 typedef struct tagSHAPEPOINT
378 } SHAPEPOINT
, *PSHAPEPOINT
;
380 #define SHAPEPOINT_TYPE_CIRCLE 'C'
381 #define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
382 #define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
384 #define SETPOINT(x, y, type) \
385 ShapePoints[*PointCount].X = (x); \
386 ShapePoints[*PointCount].Y = (y); \
387 ShapePoints[*PointCount].Type = (type); \
390 #define SETCIRCLEPOINT(x, y) \
391 SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
396 CirclePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
397 int Right
, int Bottom
)
399 int X
, X18
, X27
, X36
, X45
;
400 int Y
, Y14
, Y23
, Y58
, Y67
;
404 Even
= (0 == (Right
- Left
) % 2);
407 Radius
= (Right
- Left
) >> 1;
415 X27
= ((Left
+ Right
) >> 1) + 1;
416 X36
= (Left
+ Right
) >> 1;
420 Y58
= Top
+ Radius
+ 1;
421 Y67
= Top
+ (Right
- Left
);
422 ShapePoints
[*PointCount
].X
= X27
;
423 SETCIRCLEPOINT(X27
, Y23
);
424 SETCIRCLEPOINT(X36
, Y23
);
425 SETCIRCLEPOINT(X18
, Y14
);
426 SETCIRCLEPOINT(X45
, Y14
);
427 SETCIRCLEPOINT(X18
, Y58
);
428 SETCIRCLEPOINT(X45
, Y58
);
429 SETCIRCLEPOINT(X27
, Y67
);
430 SETCIRCLEPOINT(X36
, Y67
);
438 X27
= (Left
+ Right
) >> 1;
439 X36
= (Left
+ Right
) >> 1;
444 Y67
= Top
+ (Right
- Left
);
445 SETCIRCLEPOINT(X27
, Y23
);
446 SETCIRCLEPOINT(X45
, Y14
);
447 SETCIRCLEPOINT(X18
, Y58
);
448 SETCIRCLEPOINT(X27
, Y67
);
455 d
+= (X
<< 1) + (Even
? 4 : 3);
464 d
+= ((X
- Y
) << 1) + 5;
478 SETCIRCLEPOINT(X27
, Y23
);
479 SETCIRCLEPOINT(X36
, Y23
);
480 SETCIRCLEPOINT(X18
, Y14
);
481 SETCIRCLEPOINT(X45
, Y14
);
482 SETCIRCLEPOINT(X18
, Y58
);
483 SETCIRCLEPOINT(X45
, Y58
);
484 SETCIRCLEPOINT(X27
, Y67
);
485 SETCIRCLEPOINT(X36
, Y67
);
490 LinePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
491 int Right
, int Bottom
, int XTo
, int YTo
, BOOL Start
)
493 LONG x
, y
, deltax
, deltay
, i
, xchange
, ychange
, error
;
496 x
= (Right
+ Left
) >> 1;
497 y
= (Bottom
+ Top
) >> 1;
517 Type
= (Start
? SHAPEPOINT_TYPE_LINE_LEFT
: SHAPEPOINT_TYPE_LINE_RIGHT
);
522 Type
= (Start
? SHAPEPOINT_TYPE_LINE_RIGHT
: SHAPEPOINT_TYPE_LINE_LEFT
);
527 for (i
= x
; i
<= XTo
; i
++)
529 SETPOINT(i
, y
, Type
);
534 for (i
= y
; i
<= YTo
; i
++)
536 SETPOINT(x
, i
, Type
);
545 for (i
= 0; i
< deltay
; i
++)
547 SETPOINT(x
, y
, Type
);
549 error
= error
+ deltax
;
554 error
= error
- deltay
;
560 for (i
= 0; i
< deltax
; i
++)
562 SETPOINT(x
, y
, Type
);
564 error
= error
+ deltay
;
568 error
= error
- deltax
;
577 CompareShapePoints(const void *pv1
, const void *pv2
)
579 if (((const PSHAPEPOINT
) pv1
)->Y
< ((const PSHAPEPOINT
) pv2
)->Y
)
583 else if (((const PSHAPEPOINT
) pv2
)->Y
< ((const PSHAPEPOINT
) pv1
)->Y
)
587 else if (((const PSHAPEPOINT
) pv1
)->X
< ((const PSHAPEPOINT
) pv2
)->X
)
591 else if (((const PSHAPEPOINT
) pv2
)->X
< ((const PSHAPEPOINT
) pv1
)->X
)
619 BRUSHOBJ PenBrushObj
;
620 PBRUSHOBJ FillBrushObj
;
621 PSHAPEPOINT ShapePoints
;
622 UINT Point
, PointCount
;
624 int Y
, CircleStart
, CircleEnd
, LineStart
, LineEnd
;
627 if (Right
<= Left
|| Bottom
<= Top
)
629 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
633 if (Right
- Left
!= Bottom
- Top
)
638 dc
= DC_LockDc ( hDC
);
641 SetLastWin32Error(ERROR_INVALID_HANDLE
);
647 /* Yes, Windows really returns TRUE in this case */
651 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->Dc_Attr
.hbrush
);
652 if (NULL
== FillBrushObj
)
655 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
659 Left
+= dc
->w
.DCOrgX
;
660 Right
+= dc
->w
.DCOrgX
;
662 Bottom
+= dc
->w
.DCOrgY
;
663 XRadialStart
+= dc
->w
.DCOrgX
;
664 YRadialStart
+= dc
->w
.DCOrgY
;
665 XRadialEnd
+= dc
->w
.DCOrgX
;
666 YRadialEnd
+= dc
->w
.DCOrgY
;
668 RectBounds
.left
= Left
;
669 RectBounds
.right
= Right
;
670 RectBounds
.top
= Top
;
671 RectBounds
.bottom
= Bottom
;
673 SurfObj
= (SURFOBJ
*) AccessUserObject((ULONG
)dc
->Surface
);
674 HPenToBrushObj(&PenBrushObj
, dc
->Dc_Attr
.hpen
);
676 /* Number of points for the circle is 4 * sqrt(2) * Radius, start
677 and end line have at most Radius points, so allocate at least
679 ShapePoints
= ExAllocatePoolWithTag(PagedPool
, 8 * (Right
- Left
+ 1) / 2 * sizeof(SHAPEPOINT
), TAG_SHAPE
);
680 if (NULL
== ShapePoints
)
682 BRUSHOBJ_UnlockBrush(FillBrushObj
);
685 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
691 PUTPIXEL(Left
, Top
, &PenBrushObj
);
692 BRUSHOBJ_UnlockBrush(FillBrushObj
);
699 CirclePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
);
700 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
701 XRadialStart
, YRadialStart
, TRUE
);
702 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
703 XRadialEnd
, YRadialEnd
, FALSE
);
704 ASSERT(PointCount
<= 8 * (Right
- Left
+ 1) / 2);
705 EngSort((PBYTE
) ShapePoints
, sizeof(SHAPEPOINT
), PointCount
, CompareShapePoints
);
709 while (Point
< PointCount
)
711 Y
= ShapePoints
[Point
].Y
;
713 /* Skip any line pixels before circle */
714 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
715 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
720 /* Handle left side of circle */
721 if (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
723 CircleStart
= ShapePoints
[Point
].X
;
725 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
726 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
727 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
731 CircleEnd
= ShapePoints
[Point
- 1].X
;
733 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
736 /* Handle line(s) (max 2) inside the circle */
737 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
738 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
740 LineStart
= ShapePoints
[Point
].X
;
742 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
743 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
744 && ShapePoints
[Point
].Type
== ShapePoints
[Point
- 1].Type
)
748 LineEnd
= ShapePoints
[Point
- 1].X
;
750 PUTLINE(LineStart
, Y
, LineEnd
+ 1, Y
, &PenBrushObj
);
753 /* Handle right side of circle */
754 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
755 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
757 CircleStart
= ShapePoints
[Point
].X
;
759 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
760 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
761 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
765 CircleEnd
= ShapePoints
[Point
- 1].X
;
767 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
770 /* Skip any line pixels after circle */
771 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
777 ExFreePool(ShapePoints
);
778 BRUSHOBJ_UnlockBrush(FillBrushObj
);
789 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
790 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
791 //first and second side, between the third and fourth side, and so on.
793 //WINDING Selects winding mode (fills any region with a nonzero winding value).
794 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
795 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
796 //The direction of each edge of the polygon is important.
798 extern BOOL
FillPolygon(PDC dc
,
811 NtGdiPolyPolyDraw( IN HDC hDC
,
813 IN PULONG PolyCounts
,
819 LPINT SafePolyPoints
;
820 NTSTATUS Status
= STATUS_SUCCESS
;
822 INT nPoints
, nEmpty
, nInvalid
, i
;
824 if (iFunc
== GdiPolyPolyRgn
)
826 return (ULONG_PTR
) GdiCreatePolyPolygonRgn((CONST PPOINT
) Points
,
827 (CONST PINT
) PolyCounts
,
834 SetLastWin32Error(ERROR_INVALID_HANDLE
);
840 /* Yes, Windows really returns TRUE in this case */
849 Count
* sizeof(POINT
),
851 ProbeForRead(PolyCounts
,
857 Status
= _SEH_GetExceptionCode();
861 if (!NT_SUCCESS(Status
))
864 SetLastNtError(Status
);
868 SafePolyPoints
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_SHAPE
);
872 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
878 /* pointers already probed! */
879 RtlCopyMemory(SafePolyPoints
,
881 Count
* sizeof(INT
));
885 Status
= _SEH_GetExceptionCode();
889 if(!NT_SUCCESS(Status
))
892 ExFreePool(SafePolyPoints
);
893 SetLastNtError(Status
);
896 /* validate poligons */
900 for (i
= 0; i
< Count
; i
++)
902 if (SafePolyPoints
[i
] == 0)
906 if (SafePolyPoints
[i
] == 1)
910 nPoints
+= SafePolyPoints
[i
];
915 /* if all polygon counts are zero, return without setting a last error code. */
916 ExFreePool(SafePolyPoints
);
921 /* if at least one poly count is 1, fail */
922 ExFreePool(SafePolyPoints
);
923 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
927 Safept
= ExAllocatePoolWithTag(PagedPool
, nPoints
* sizeof(POINT
), TAG_SHAPE
);
931 ExFreePool(SafePolyPoints
);
932 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
938 /* pointers already probed! */
939 RtlCopyMemory(Safept
,
941 nPoints
* sizeof(POINT
));
945 Status
= _SEH_GetExceptionCode();
949 if(!NT_SUCCESS(Status
))
952 ExFreePool(SafePolyPoints
);
954 SetLastNtError(Status
);
961 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
968 Ret
= IntGdiPolyPolygon(dc
, Safept
, SafePolyPoints
, Count
);
970 case GdiPolyPolyLine
:
971 Ret
= IntGdiPolyPolyline(dc
, Safept
, (LPDWORD
) SafePolyPoints
, Count
);
974 Ret
= IntGdiPolyBezier(dc
, Safept
, *PolyCounts
);
977 Ret
= IntGdiPolylineTo(dc
, Safept
, *PolyCounts
);
979 case GdiPolyBezierTo
:
980 Ret
= IntGdiPolyBezierTo(dc
, Safept
, *PolyCounts
);
983 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
986 ExFreePool(SafePolyPoints
);
990 return (ULONG_PTR
) Ret
;
1002 BITMAPOBJ
*BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1003 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1004 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
1005 BOOL ret
= FALSE
; // default to failure
1009 ASSERT ( dc
); // caller's responsibility to set this up
1010 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1011 ASSERT ( BitmapObj
);
1013 if ( PATH_IsPathOpen(dc
->w
.path
) )
1015 ret
= PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1019 LeftRect
+= dc
->w
.DCOrgX
;
1020 RightRect
+= dc
->w
.DCOrgX
- 1;
1021 TopRect
+= dc
->w
.DCOrgY
;
1022 BottomRect
+= dc
->w
.DCOrgY
- 1;
1024 DestRect
.left
= LeftRect
;
1025 DestRect
.right
= RightRect
;
1026 DestRect
.top
= TopRect
;
1027 DestRect
.bottom
= BottomRect
;
1029 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->Dc_Attr
.hbrush
);
1033 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1035 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1036 ret
= IntEngBitBlt(&BitmapObj
->SurfObj
,
1044 &FillBrushInst
.BrushObject
,
1046 ROP3_TO_ROP4(PATCOPY
));
1050 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1052 /* get BRUSHOBJ from current pen. */
1053 PenBrushObj
= PENOBJ_LockPen(dc
->Dc_Attr
.hpen
);
1054 if (PenBrushObj
== NULL
)
1056 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1057 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1061 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1063 // Draw the rectangle with the current pen
1065 ret
= TRUE
; // change default to success
1067 if (!(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1069 Mix
= ROP2_TO_MIX(dc
->Dc_Attr
.jROP2
);
1070 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1072 &PenBrushInst
.BrushObject
,
1073 LeftRect
, TopRect
, RightRect
, TopRect
,
1074 &DestRect
, // Bounding rectangle
1077 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1079 &PenBrushInst
.BrushObject
,
1080 RightRect
, TopRect
, RightRect
, BottomRect
,
1081 &DestRect
, // Bounding rectangle
1084 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1086 &PenBrushInst
.BrushObject
,
1087 RightRect
, BottomRect
, LeftRect
, BottomRect
,
1088 &DestRect
, // Bounding rectangle
1091 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1093 &PenBrushInst
.BrushObject
,
1094 LeftRect
, BottomRect
, LeftRect
, TopRect
,
1095 &DestRect
, // Bounding rectangle
1099 PENOBJ_UnlockPen(PenBrushObj
);
1102 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1104 /* Move current position in DC?
1105 MSDN: The current position is neither used nor updated by Rectangle. */
1112 NtGdiRectangle(HDC hDC
,
1119 BOOL ret
; // default to failure
1121 dc
= DC_LockDc(hDC
);
1124 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1130 /* Yes, Windows really returns TRUE in this case */
1134 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1152 BITMAPOBJ
*BitmapObj
;
1153 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1154 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
1156 int potential_steps
;
1157 int i
, col
, row
, width
, height
, x1
, x1start
, x2
, x2start
, y1
, y2
;
1158 int xradius
, yradius
;
1159 //float aspect_square;
1160 long a_square
, b_square
,
1161 two_a_square
, two_b_square
,
1162 four_a_square
, four_b_square
,
1165 ret
= TRUE
; // default to success
1167 ASSERT ( dc
); // caller's responsibility to set this up
1169 if ( PATH_IsPathOpen(dc
->w
.path
) )
1170 return PATH_RoundRect ( dc
, left
, top
, right
, bottom
,
1171 xCurveDiameter
, yCurveDiameter
);
1173 xradius
= xCurveDiameter
>> 1;
1174 yradius
= yCurveDiameter
>> 1;
1176 left
+= dc
->w
.DCOrgX
;
1177 right
+= dc
->w
.DCOrgX
;
1178 top
+= dc
->w
.DCOrgY
;
1179 bottom
+= dc
->w
.DCOrgY
;
1181 RectBounds
.left
= left
;
1182 RectBounds
.right
= right
;
1183 RectBounds
.top
= top
;
1184 RectBounds
.bottom
= bottom
;
1186 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1189 /* Nothing to do, as we don't have a bitmap */
1190 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1194 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->Dc_Attr
.hbrush
);
1197 if (FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1199 /* make null brush check simpler... */
1200 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1201 FillBrushObj
= NULL
;
1205 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1209 PenBrushObj
= PENOBJ_LockPen(dc
->Dc_Attr
.hpen
);
1212 if (PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1214 /* make null pen check simpler... */
1215 PENOBJ_UnlockPen(PenBrushObj
);
1220 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1227 width
= right
- left
;
1228 height
= bottom
- top
;
1230 if ( (xradius
<<1) > width
)
1231 xradius
= width
>> 1;
1232 if ( (yradius
<<1) > height
)
1233 yradius
= height
>> 1;
1235 b_square
= yradius
* yradius
;
1236 a_square
= xradius
* xradius
;
1239 two_a_square
= a_square
<< 1;
1240 four_a_square
= a_square
<< 2;
1241 four_b_square
= b_square
<< 2;
1242 two_b_square
= b_square
<< 1;
1243 d
= two_a_square
* ((row
- 1) * (row
))
1245 + two_b_square
* (1 - a_square
);
1255 dinc
= two_b_square
*3; /* two_b_square * (3 + (col << 1)); */
1256 ddec
= four_a_square
* row
;
1264 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1271 PUTLINE ( x1
, y1
, x1start
, y1
, PenBrushInst
);
1272 PUTLINE ( x2start
+1, y2
, x2
+1, y2
, PenBrushInst
);
1276 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1277 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1285 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1288 if ( x1start
>= x1
)
1290 PUTLINE ( x1
, y1
, x1start
+1, y1
, PenBrushInst
);
1291 PUTLINE ( x2start
, y2
, x2
+1, y2
, PenBrushInst
);
1295 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1296 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1304 PUTLINE ( x1
, y2
, x1start
+1, y2
, PenBrushInst
);
1305 PUTLINE ( x2start
, y1
, x2
+1, y1
, PenBrushInst
);
1309 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1310 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1315 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1319 potential_steps
= ( a_square
* row
) / b_square
- col
+ 1;
1320 while ( d
< 0 && potential_steps
-- )
1322 d
+= dinc
; /* two_b_square * (3 + (col << 1)); */
1323 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1326 if ( a_square
* row
<= b_square
* col
)
1330 d
= two_b_square
* (col
+ 1) * col
1331 + two_a_square
* (row
* (row
- 2) + 1)
1332 + (1 - two_a_square
) * b_square
;
1333 dinc
= ddec
; /* four_b_square * col; */
1334 ddec
= two_a_square
* ((row
<< 1) - 3);
1340 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1341 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1345 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1346 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1347 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1348 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1353 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1354 d
+= dinc
; //four_b_square * col;
1357 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1358 d
-= ddec
; //two_a_square * ((row << 1) - 3);
1363 PUTLINE ( left
, y1
, right
, y1
, FillBrushInst
);
1364 PUTLINE ( left
, y2
, right
, y2
, FillBrushInst
);
1368 if ( x1
> (left
+1) )
1370 PUTLINE ( left
, y1
, x1
, y1
, PenBrushInst
);
1371 PUTLINE ( x2
+1, y1
, right
, y1
, PenBrushInst
);
1372 PUTLINE ( left
+1, y2
, x1
, y2
, PenBrushInst
);
1373 PUTLINE ( x2
+1, y2
, right
+1, y2
, PenBrushInst
);
1377 PUTPIXEL ( left
, y1
, PenBrushInst
);
1378 PUTPIXEL ( right
, y2
, PenBrushInst
);
1385 y2
= bottom
-yradius
;
1389 for ( i
= y1
+1; i
< y2
; i
++ )
1390 PUTLINE ( left
, i
, right
, i
, FillBrushInst
);
1395 PUTLINE ( x1
, top
, x2
, top
, PenBrushInst
);
1396 PUTLINE ( right
, y1
, right
, y2
, PenBrushInst
);
1397 PUTLINE ( x2
, bottom
, x1
, bottom
, PenBrushInst
);
1398 PUTLINE ( left
, y2
, left
, y1
, PenBrushInst
);
1401 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1402 if(PenBrushObj
!= NULL
)
1403 PENOBJ_UnlockPen(PenBrushObj
);
1404 if(FillBrushObj
!= NULL
)
1405 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1421 DC
*dc
= DC_LockDc(hDC
);
1422 BOOL ret
= FALSE
; /* default to failure */
1424 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
1427 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
1428 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1433 /* Yes, Windows really returns TRUE in this case */
1438 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
1454 BITMAPOBJ
*BitmapObj
;
1468 /* check parameters */
1469 if(ulMode
& GRADIENT_FILL_TRIANGLE
)
1471 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
1473 for(i
= 0; i
< uMesh
; i
++, tr
++)
1475 if(tr
->Vertex1
>= uVertex
||
1476 tr
->Vertex2
>= uVertex
||
1477 tr
->Vertex3
>= uVertex
)
1479 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1486 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
1487 for(i
= 0; i
< uMesh
; i
++, rc
++)
1489 if(rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
1491 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1497 /* calculate extent */
1498 Extent
.left
= Extent
.right
= pVertex
->x
;
1499 Extent
.top
= Extent
.bottom
= pVertex
->y
;
1500 for(i
= 0; i
< uVertex
; i
++)
1502 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
1503 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
1504 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
1505 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
1508 DitherOrg
.x
= dc
->w
.DCOrgX
;
1509 DitherOrg
.y
= dc
->w
.DCOrgY
;
1510 Extent
.left
+= DitherOrg
.x
;
1511 Extent
.right
+= DitherOrg
.x
;
1512 Extent
.top
+= DitherOrg
.y
;
1513 Extent
.bottom
+= DitherOrg
.y
;
1515 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1516 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1519 PalDestGDI
= PALETTE_LockPalette(dc
->w
.hPalette
);
1520 /* FIXME - PalDestGDI can be NULL!!! Don't assert but handle this case gracefully! */
1522 Mode
= PalDestGDI
->Mode
;
1523 PALETTE_UnlockPalette(PalDestGDI
);
1525 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
1528 Ret
= IntEngGradientFill(&BitmapObj
->SurfObj
,
1539 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1540 EngDeleteXlate(XlateObj
);
1557 PTRIVERTEX SafeVertex
;
1560 NTSTATUS Status
= STATUS_SUCCESS
;
1562 dc
= DC_LockDc(hdc
);
1565 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1571 /* Yes, Windows really returns TRUE in this case */
1574 if(!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
1577 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1583 case GRADIENT_FILL_RECT_H
:
1584 case GRADIENT_FILL_RECT_V
:
1585 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
1587 case GRADIENT_FILL_TRIANGLE
:
1588 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
1592 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1598 ProbeForRead(pVertex
,
1599 uVertex
* sizeof(TRIVERTEX
),
1607 Status
= _SEH_GetExceptionCode();
1611 if (!NT_SUCCESS(Status
))
1614 SetLastWin32Error(Status
);
1618 if(!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1621 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1625 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1629 /* pointers were already probed! */
1630 RtlCopyMemory(SafeVertex
,
1632 uVertex
* sizeof(TRIVERTEX
));
1633 RtlCopyMemory(SafeMesh
,
1639 Status
= _SEH_GetExceptionCode();
1643 if(!NT_SUCCESS(Status
))
1646 ExFreePool(SafeVertex
);
1647 SetLastNtError(Status
);
1651 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1654 ExFreePool(SafeVertex
);
1666 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1668 /* lie and say we succeded */