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_Attr->jROP2));
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
39 &BrushInst.BrushObject, \
42 ROP2_TO_MIX(Dc_Attr->jROP2));
50 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
51 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
52 BOOL ret
= FALSE
; // default to failure
57 ASSERT(dc
); // caller's responsibility to pass a valid dc
59 if ( NULL
== UnsafePoints
|| Count
< 2 )
61 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
65 Dc_Attr
= dc
->pDc_Attr
;
66 if (!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
68 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
69 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
72 /* Convert to screen coordinates */
73 IntLPtoDP(dc
, UnsafePoints
, Count
);
74 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
76 UnsafePoints
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
77 UnsafePoints
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
80 if (PATH_IsPathOpen(dc
->w
.path
))
81 ret
= PATH_Polygon(dc
, UnsafePoints
, Count
);
84 DestRect
.left
= UnsafePoints
[0].x
;
85 DestRect
.right
= UnsafePoints
[0].x
;
86 DestRect
.top
= UnsafePoints
[0].y
;
87 DestRect
.bottom
= UnsafePoints
[0].y
;
89 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
91 DestRect
.left
= min(DestRect
.left
, UnsafePoints
[CurrentPoint
].x
);
92 DestRect
.right
= max(DestRect
.right
, UnsafePoints
[CurrentPoint
].x
);
93 DestRect
.top
= min(DestRect
.top
, UnsafePoints
[CurrentPoint
].y
);
94 DestRect
.bottom
= max(DestRect
.bottom
, UnsafePoints
[CurrentPoint
].y
);
97 /* Now fill the polygon with the current brush. */
98 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
99 if (FillBrushObj
&& !(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
101 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
102 ret
= FillPolygon ( dc
, BitmapObj
, &FillBrushInst
.BrushObject
, ROP2_TO_MIX(Dc_Attr
->jROP2
), UnsafePoints
, Count
, DestRect
);
104 BRUSHOBJ_UnlockBrush(FillBrushObj
);
106 /* get BRUSHOBJ from current pen. */
107 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
108 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
109 if (PenBrushObj
&& !(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
113 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
115 for (i
= 0; i
< Count
-1; i
++)
118 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
119 // UnsafePoints[0].x, UnsafePoints[0].y,
120 // UnsafePoints[1].x, UnsafePoints[1].y );
122 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
124 &PenBrushInst
.BrushObject
,
125 UnsafePoints
[i
].x
, /* From */
127 UnsafePoints
[i
+1].x
, /* To */
130 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
133 /* Close the polygon */
136 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
138 &PenBrushInst
.BrushObject
,
139 UnsafePoints
[Count
-1].x
, /* From */
140 UnsafePoints
[Count
-1].y
,
141 UnsafePoints
[0].x
, /* To */
144 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
147 PENOBJ_UnlockPen(PenBrushObj
);
149 BITMAPOBJ_UnlockBitmap(BitmapObj
);
155 IntGdiPolyPolygon(DC
*dc
,
162 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
164 Points
+=*PolyCounts
++;
169 /******************************************************************************/
178 * This function uses optimized Bresenham's ellipse algorithm. It draws
179 * four lines of the ellipse in one pass.
182 * Make it look like a Windows ellipse.
196 int NewA
, NewB
, NewC
, NewD
;
198 int CenterX
, CenterY
;
199 int RadiusX
, RadiusY
;
201 PGDIBRUSHOBJ FillBrush
, PenBrush
;
202 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
203 BITMAPOBJ
*BitmapObj
;
207 BOOL ret
= TRUE
, Cond1
, Cond2
;
210 * Check the parameters.
213 if (nRightRect
<= nLeftRect
|| nBottomRect
<= nTopRect
)
215 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
220 * Get pointers to all necessary GDI objects.
226 SetLastWin32Error(ERROR_INVALID_HANDLE
);
229 if (dc
->DC_Type
== DC_TYPE_INFO
)
232 /* Yes, Windows really returns TRUE in this case */
236 Dc_Attr
= dc
->pDc_Attr
;
237 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
239 FillBrush
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
240 if (NULL
== FillBrush
)
243 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
247 PenBrush
= PENOBJ_LockPen(Dc_Attr
->hpen
);
248 if (NULL
== PenBrush
)
250 BRUSHOBJ_UnlockBrush(FillBrush
);
252 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
256 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
257 if (NULL
== BitmapObj
)
259 BRUSHOBJ_UnlockBrush(FillBrush
);
260 PENOBJ_UnlockPen(PenBrush
);
262 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
266 IntGdiInitBrushInstance(&FillBrushInst
, FillBrush
, dc
->XlateBrush
);
267 IntGdiInitBrushInstance(&PenBrushInst
, PenBrush
, dc
->XlatePen
);
269 RectBounds
.left
= nLeftRect
;
270 RectBounds
.right
= nRightRect
;
271 RectBounds
.top
= nTopRect
;
272 RectBounds
.bottom
= nBottomRect
;
274 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
276 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
277 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
278 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
279 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
281 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) >> 1, 1);
282 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) >> 1, 1);
283 CenterX
= RectBounds
.left
+ RadiusX
;
284 CenterY
= RectBounds
.top
+ RadiusY
;
286 if (RadiusX
> RadiusY
)
302 NewB
= (iy
+ 32) >> 6;
304 NewD
= (NewB
* ny
) / nx
;
314 NewA
= (ix
+ 32) >> 6;
315 NewB
= (iy
+ 32) >> 6;
316 NewC
= (NewA
* ny
) / nx
;
317 NewD
= (NewB
* ny
) / nx
;
319 if (RadiusX
> RadiusY
)
321 Temp
= A
; A
= C
; C
= Temp
;
322 Temp
= B
; B
= D
; D
= Temp
;
323 Cond1
= ((C
!= NewA
) || (B
!= NewD
)) && (NewC
<= NewD
);
324 Cond2
= ((D
!= NewB
) || (A
!= NewC
)) && (NewC
<= B
);
328 Cond1
= ((C
!= NewC
) || (B
!= NewB
)) && (NewA
<= NewB
);
329 Cond2
= ((D
!= NewD
) || (A
!= NewA
)) && (NewA
<= B
);
333 * Draw the lines going from inner to outer (+ mirrored).
336 if ((A
> da
) && (A
< db
))
338 PUTLINE(CenterX
- D
, CenterY
+ A
, CenterX
+ D
, CenterY
+ A
, FillBrushInst
);
341 PUTLINE(CenterX
- D
, CenterY
- A
, CenterX
+ D
, CenterY
- A
, FillBrushInst
);
347 * Draw the lines going from outer to inner (+ mirrored).
350 if ((B
< db
) && (B
> da
))
352 PUTLINE(CenterX
- C
, CenterY
+ B
, CenterX
+ C
, CenterY
+ B
, FillBrushInst
);
353 PUTLINE(CenterX
- C
, CenterY
- B
, CenterX
+ C
, CenterY
- B
, FillBrushInst
);
358 * Draw the pixels on the margin.
363 PUTPIXEL(CenterX
+ C
, CenterY
+ B
, PenBrushInst
);
365 PUTPIXEL(CenterX
- C
, CenterY
+ B
, PenBrushInst
);
368 PUTPIXEL(CenterX
+ C
, CenterY
- B
, PenBrushInst
);
370 PUTPIXEL(CenterX
- C
, CenterY
- B
, PenBrushInst
);
376 PUTPIXEL(CenterX
+ D
, CenterY
+ A
, PenBrushInst
);
378 PUTPIXEL(CenterX
- D
, CenterY
+ A
, PenBrushInst
);
381 PUTPIXEL(CenterX
+ D
, CenterY
- A
, PenBrushInst
);
383 PUTPIXEL(CenterX
- D
, CenterY
- A
, PenBrushInst
);
388 BITMAPOBJ_UnlockBitmap(BitmapObj
);
389 BRUSHOBJ_UnlockBrush(FillBrush
);
390 PENOBJ_UnlockPen(PenBrush
);
396 typedef struct tagSHAPEPOINT
401 } SHAPEPOINT
, *PSHAPEPOINT
;
403 #define SHAPEPOINT_TYPE_CIRCLE 'C'
404 #define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
405 #define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
407 #define SETPOINT(x, y, type) \
408 ShapePoints[*PointCount].X = (x); \
409 ShapePoints[*PointCount].Y = (y); \
410 ShapePoints[*PointCount].Type = (type); \
413 #define SETCIRCLEPOINT(x, y) \
414 SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
419 CirclePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
420 int Right
, int Bottom
)
422 int X
, X18
, X27
, X36
, X45
;
423 int Y
, Y14
, Y23
, Y58
, Y67
;
427 Even
= (0 == (Right
- Left
) % 2);
430 Radius
= (Right
- Left
) >> 1;
438 X27
= ((Left
+ Right
) >> 1) + 1;
439 X36
= (Left
+ Right
) >> 1;
443 Y58
= Top
+ Radius
+ 1;
444 Y67
= Top
+ (Right
- Left
);
445 ShapePoints
[*PointCount
].X
= X27
;
446 SETCIRCLEPOINT(X27
, Y23
);
447 SETCIRCLEPOINT(X36
, Y23
);
448 SETCIRCLEPOINT(X18
, Y14
);
449 SETCIRCLEPOINT(X45
, Y14
);
450 SETCIRCLEPOINT(X18
, Y58
);
451 SETCIRCLEPOINT(X45
, Y58
);
452 SETCIRCLEPOINT(X27
, Y67
);
453 SETCIRCLEPOINT(X36
, Y67
);
461 X27
= (Left
+ Right
) >> 1;
462 X36
= (Left
+ Right
) >> 1;
467 Y67
= Top
+ (Right
- Left
);
468 SETCIRCLEPOINT(X27
, Y23
);
469 SETCIRCLEPOINT(X45
, Y14
);
470 SETCIRCLEPOINT(X18
, Y58
);
471 SETCIRCLEPOINT(X27
, Y67
);
478 d
+= (X
<< 1) + (Even
? 4 : 3);
487 d
+= ((X
- Y
) << 1) + 5;
501 SETCIRCLEPOINT(X27
, Y23
);
502 SETCIRCLEPOINT(X36
, Y23
);
503 SETCIRCLEPOINT(X18
, Y14
);
504 SETCIRCLEPOINT(X45
, Y14
);
505 SETCIRCLEPOINT(X18
, Y58
);
506 SETCIRCLEPOINT(X45
, Y58
);
507 SETCIRCLEPOINT(X27
, Y67
);
508 SETCIRCLEPOINT(X36
, Y67
);
513 LinePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
514 int Right
, int Bottom
, int XTo
, int YTo
, BOOL Start
)
516 LONG x
, y
, deltax
, deltay
, i
, xchange
, ychange
, error
;
519 x
= (Right
+ Left
) >> 1;
520 y
= (Bottom
+ Top
) >> 1;
540 Type
= (Start
? SHAPEPOINT_TYPE_LINE_LEFT
: SHAPEPOINT_TYPE_LINE_RIGHT
);
545 Type
= (Start
? SHAPEPOINT_TYPE_LINE_RIGHT
: SHAPEPOINT_TYPE_LINE_LEFT
);
550 for (i
= x
; i
<= XTo
; i
++)
552 SETPOINT(i
, y
, Type
);
557 for (i
= y
; i
<= YTo
; i
++)
559 SETPOINT(x
, i
, Type
);
568 for (i
= 0; i
< deltay
; i
++)
570 SETPOINT(x
, y
, Type
);
572 error
= error
+ deltax
;
577 error
= error
- deltay
;
583 for (i
= 0; i
< deltax
; i
++)
585 SETPOINT(x
, y
, Type
);
587 error
= error
+ deltay
;
591 error
= error
- deltax
;
600 CompareShapePoints(const void *pv1
, const void *pv2
)
602 if (((const PSHAPEPOINT
) pv1
)->Y
< ((const PSHAPEPOINT
) pv2
)->Y
)
606 else if (((const PSHAPEPOINT
) pv2
)->Y
< ((const PSHAPEPOINT
) pv1
)->Y
)
610 else if (((const PSHAPEPOINT
) pv1
)->X
< ((const PSHAPEPOINT
) pv2
)->X
)
614 else if (((const PSHAPEPOINT
) pv2
)->X
< ((const PSHAPEPOINT
) pv1
)->X
)
643 BRUSHOBJ PenBrushObj
;
644 PBRUSHOBJ FillBrushObj
;
645 PSHAPEPOINT ShapePoints
;
646 UINT Point
, PointCount
;
648 int Y
, CircleStart
, CircleEnd
, LineStart
, LineEnd
;
651 if (Right
<= Left
|| Bottom
<= Top
)
653 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
657 if (Right
- Left
!= Bottom
- Top
)
662 dc
= DC_LockDc ( hDC
);
665 SetLastWin32Error(ERROR_INVALID_HANDLE
);
668 if (dc
->DC_Type
== DC_TYPE_INFO
)
671 /* Yes, Windows really returns TRUE in this case */
675 Dc_Attr
= dc
->pDc_Attr
;
676 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
678 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
679 if (NULL
== FillBrushObj
)
682 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
686 Left
+= dc
->ptlDCOrig
.x
;
687 Right
+= dc
->ptlDCOrig
.x
;
688 Top
+= dc
->ptlDCOrig
.y
;
689 Bottom
+= dc
->ptlDCOrig
.y
;
690 XRadialStart
+= dc
->ptlDCOrig
.x
;
691 YRadialStart
+= dc
->ptlDCOrig
.y
;
692 XRadialEnd
+= dc
->ptlDCOrig
.x
;
693 YRadialEnd
+= dc
->ptlDCOrig
.y
;
695 RectBounds
.left
= Left
;
696 RectBounds
.right
= Right
;
697 RectBounds
.top
= Top
;
698 RectBounds
.bottom
= Bottom
;
700 SurfObj
= (SURFOBJ
*) AccessUserObject((ULONG
)dc
->Surface
);
701 HPenToBrushObj(&PenBrushObj
, Dc_Attr
->hpen
);
703 /* Number of points for the circle is 4 * sqrt(2) * Radius, start
704 and end line have at most Radius points, so allocate at least
706 ShapePoints
= ExAllocatePoolWithTag(PagedPool
, 8 * (Right
- Left
+ 1) / 2 * sizeof(SHAPEPOINT
), TAG_SHAPE
);
707 if (NULL
== ShapePoints
)
709 BRUSHOBJ_UnlockBrush(FillBrushObj
);
712 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
718 PUTPIXEL(Left
, Top
, &PenBrushObj
);
719 BRUSHOBJ_UnlockBrush(FillBrushObj
);
726 CirclePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
);
727 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
728 XRadialStart
, YRadialStart
, TRUE
);
729 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
730 XRadialEnd
, YRadialEnd
, FALSE
);
731 ASSERT(PointCount
<= 8 * (Right
- Left
+ 1) / 2);
732 EngSort((PBYTE
) ShapePoints
, sizeof(SHAPEPOINT
), PointCount
, CompareShapePoints
);
736 while (Point
< PointCount
)
738 Y
= ShapePoints
[Point
].Y
;
740 /* Skip any line pixels before circle */
741 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
742 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
747 /* Handle left side of circle */
748 if (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
750 CircleStart
= ShapePoints
[Point
].X
;
752 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
753 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
754 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
758 CircleEnd
= ShapePoints
[Point
- 1].X
;
760 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
763 /* Handle line(s) (max 2) inside the circle */
764 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
765 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
767 LineStart
= ShapePoints
[Point
].X
;
769 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
770 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
771 && ShapePoints
[Point
].Type
== ShapePoints
[Point
- 1].Type
)
775 LineEnd
= ShapePoints
[Point
- 1].X
;
777 PUTLINE(LineStart
, Y
, LineEnd
+ 1, Y
, &PenBrushObj
);
780 /* Handle right side of circle */
781 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
782 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
784 CircleStart
= ShapePoints
[Point
].X
;
786 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
787 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
788 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
792 CircleEnd
= ShapePoints
[Point
- 1].X
;
794 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
797 /* Skip any line pixels after circle */
798 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
804 ExFreePool(ShapePoints
);
805 BRUSHOBJ_UnlockBrush(FillBrushObj
);
816 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
817 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
818 //first and second side, between the third and fourth side, and so on.
820 //WINDING Selects winding mode (fills any region with a nonzero winding value).
821 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
822 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
823 //The direction of each edge of the polygon is important.
825 extern BOOL
FillPolygon(PDC dc
,
838 NtGdiPolyPolyDraw( IN HDC hDC
,
840 IN PULONG PolyCounts
,
846 LPINT SafePolyPoints
;
847 NTSTATUS Status
= STATUS_SUCCESS
;
849 INT nPoints
, nEmpty
, nInvalid
, i
;
851 if (iFunc
== GdiPolyPolyRgn
)
853 return (ULONG_PTR
) GdiCreatePolyPolygonRgn((CONST PPOINT
) Points
,
854 (CONST PINT
) PolyCounts
,
861 SetLastWin32Error(ERROR_INVALID_HANDLE
);
864 if (dc
->DC_Type
== DC_TYPE_INFO
)
867 /* Yes, Windows really returns TRUE in this case */
876 Count
* sizeof(POINT
),
878 ProbeForRead(PolyCounts
,
884 Status
= _SEH_GetExceptionCode();
888 if (!NT_SUCCESS(Status
))
891 SetLastNtError(Status
);
895 SafePolyPoints
= ExAllocatePoolWithTag(PagedPool
, Count
* sizeof(INT
), TAG_SHAPE
);
899 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
905 /* pointers already probed! */
906 RtlCopyMemory(SafePolyPoints
,
908 Count
* sizeof(INT
));
912 Status
= _SEH_GetExceptionCode();
916 if (!NT_SUCCESS(Status
))
919 ExFreePool(SafePolyPoints
);
920 SetLastNtError(Status
);
923 /* validate poligons */
927 for (i
= 0; i
< Count
; i
++)
929 if (SafePolyPoints
[i
] == 0)
933 if (SafePolyPoints
[i
] == 1)
937 nPoints
+= SafePolyPoints
[i
];
942 /* if all polygon counts are zero, return without setting a last error code. */
943 ExFreePool(SafePolyPoints
);
948 /* if at least one poly count is 1, fail */
949 ExFreePool(SafePolyPoints
);
950 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
954 Safept
= ExAllocatePoolWithTag(PagedPool
, nPoints
* sizeof(POINT
), TAG_SHAPE
);
958 ExFreePool(SafePolyPoints
);
959 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
965 /* pointers already probed! */
966 RtlCopyMemory(Safept
,
968 nPoints
* sizeof(POINT
));
972 Status
= _SEH_GetExceptionCode();
976 if (!NT_SUCCESS(Status
))
979 ExFreePool(SafePolyPoints
);
981 SetLastNtError(Status
);
988 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
995 Ret
= IntGdiPolyPolygon(dc
, Safept
, SafePolyPoints
, Count
);
997 case GdiPolyPolyLine
:
998 Ret
= IntGdiPolyPolyline(dc
, Safept
, (LPDWORD
) SafePolyPoints
, Count
);
1001 Ret
= IntGdiPolyBezier(dc
, Safept
, *PolyCounts
);
1004 Ret
= IntGdiPolylineTo(dc
, Safept
, *PolyCounts
);
1006 case GdiPolyBezierTo
:
1007 Ret
= IntGdiPolyBezierTo(dc
, Safept
, *PolyCounts
);
1010 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1013 ExFreePool(SafePolyPoints
);
1017 return (ULONG_PTR
) Ret
;
1023 IntRectangle(PDC dc
,
1029 BITMAPOBJ
*BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1030 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1031 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
1032 BOOL ret
= FALSE
; // default to failure
1037 ASSERT ( dc
); // caller's responsibility to set this up
1038 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1039 ASSERT ( BitmapObj
);
1041 Dc_Attr
= dc
->pDc_Attr
;
1042 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1044 if ( PATH_IsPathOpen(dc
->w
.path
) )
1046 ret
= PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1050 LeftRect
+= dc
->ptlDCOrig
.x
;
1051 RightRect
+= dc
->ptlDCOrig
.x
- 1;
1052 TopRect
+= dc
->ptlDCOrig
.y
;
1053 BottomRect
+= dc
->ptlDCOrig
.y
- 1;
1055 DestRect
.left
= LeftRect
;
1056 DestRect
.right
= RightRect
;
1057 DestRect
.top
= TopRect
;
1058 DestRect
.bottom
= BottomRect
;
1060 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1064 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1066 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1067 ret
= IntEngBitBlt(&BitmapObj
->SurfObj
,
1075 &FillBrushInst
.BrushObject
,
1077 ROP3_TO_ROP4(PATCOPY
));
1081 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1083 /* get BRUSHOBJ from current pen. */
1084 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
1085 if (PenBrushObj
== NULL
)
1087 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1088 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1092 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1094 // Draw the rectangle with the current pen
1096 ret
= TRUE
; // change default to success
1098 if (!(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1100 Mix
= ROP2_TO_MIX(Dc_Attr
->jROP2
);
1101 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1103 &PenBrushInst
.BrushObject
,
1104 LeftRect
, TopRect
, RightRect
, TopRect
,
1105 &DestRect
, // Bounding rectangle
1108 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1110 &PenBrushInst
.BrushObject
,
1111 RightRect
, TopRect
, RightRect
, BottomRect
,
1112 &DestRect
, // Bounding rectangle
1115 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1117 &PenBrushInst
.BrushObject
,
1118 RightRect
, BottomRect
, LeftRect
, BottomRect
,
1119 &DestRect
, // Bounding rectangle
1122 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1124 &PenBrushInst
.BrushObject
,
1125 LeftRect
, BottomRect
, LeftRect
, TopRect
,
1126 &DestRect
, // Bounding rectangle
1130 PENOBJ_UnlockPen(PenBrushObj
);
1133 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1135 /* Move current position in DC?
1136 MSDN: The current position is neither used nor updated by Rectangle. */
1143 NtGdiRectangle(HDC hDC
,
1150 BOOL ret
; // default to failure
1152 dc
= DC_LockDc(hDC
);
1155 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1158 if (dc
->DC_Type
== DC_TYPE_INFO
)
1161 /* Yes, Windows really returns TRUE in this case */
1165 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1184 BITMAPOBJ
*BitmapObj
;
1185 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1186 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
1188 int potential_steps
;
1189 int i
, col
, row
, width
, height
, x1
, x1start
, x2
, x2start
, y1
, y2
;
1190 int xradius
, yradius
;
1191 //float aspect_square;
1192 long a_square
, b_square
,
1193 two_a_square
, two_b_square
,
1194 four_a_square
, four_b_square
,
1197 ret
= TRUE
; // default to success
1199 ASSERT ( dc
); // caller's responsibility to set this up
1201 if ( PATH_IsPathOpen(dc
->w
.path
) )
1202 return PATH_RoundRect ( dc
, left
, top
, right
, bottom
,
1203 xCurveDiameter
, yCurveDiameter
);
1204 Dc_Attr
= dc
->pDc_Attr
;
1205 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1207 xradius
= xCurveDiameter
>> 1;
1208 yradius
= yCurveDiameter
>> 1;
1210 left
+= dc
->ptlDCOrig
.x
;
1211 right
+= dc
->ptlDCOrig
.x
;
1212 top
+= dc
->ptlDCOrig
.y
;
1213 bottom
+= dc
->ptlDCOrig
.y
;
1215 RectBounds
.left
= left
;
1216 RectBounds
.right
= right
;
1217 RectBounds
.top
= top
;
1218 RectBounds
.bottom
= bottom
;
1220 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1223 /* Nothing to do, as we don't have a bitmap */
1224 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1228 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1231 if (FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1233 /* make null brush check simpler... */
1234 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1235 FillBrushObj
= NULL
;
1239 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1243 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
1246 if (PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1248 /* make null pen check simpler... */
1249 PENOBJ_UnlockPen(PenBrushObj
);
1254 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1261 width
= right
- left
;
1262 height
= bottom
- top
;
1264 if ( (xradius
<<1) > width
)
1265 xradius
= width
>> 1;
1266 if ( (yradius
<<1) > height
)
1267 yradius
= height
>> 1;
1269 b_square
= yradius
* yradius
;
1270 a_square
= xradius
* xradius
;
1273 two_a_square
= a_square
<< 1;
1274 four_a_square
= a_square
<< 2;
1275 four_b_square
= b_square
<< 2;
1276 two_b_square
= b_square
<< 1;
1277 d
= two_a_square
* ((row
- 1) * (row
))
1279 + two_b_square
* (1 - a_square
);
1289 dinc
= two_b_square
*3; /* two_b_square * (3 + (col << 1)); */
1290 ddec
= four_a_square
* row
;
1298 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1305 PUTLINE ( x1
, y1
, x1start
, y1
, PenBrushInst
);
1306 PUTLINE ( x2start
+1, y2
, x2
+1, y2
, PenBrushInst
);
1310 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1311 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1319 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1322 if ( x1start
>= x1
)
1324 PUTLINE ( x1
, y1
, x1start
+1, y1
, PenBrushInst
);
1325 PUTLINE ( x2start
, y2
, x2
+1, y2
, PenBrushInst
);
1329 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1330 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1338 PUTLINE ( x1
, y2
, x1start
+1, y2
, PenBrushInst
);
1339 PUTLINE ( x2start
, y1
, x2
+1, y1
, PenBrushInst
);
1343 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1344 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1349 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1353 potential_steps
= ( a_square
* row
) / b_square
- col
+ 1;
1354 while ( d
< 0 && potential_steps
-- )
1356 d
+= dinc
; /* two_b_square * (3 + (col << 1)); */
1357 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1360 if ( a_square
* row
<= b_square
* col
)
1364 d
= two_b_square
* (col
+ 1) * col
1365 + two_a_square
* (row
* (row
- 2) + 1)
1366 + (1 - two_a_square
) * b_square
;
1367 dinc
= ddec
; /* four_b_square * col; */
1368 ddec
= two_a_square
* ((row
<< 1) - 3);
1374 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1375 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1379 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1380 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1381 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1382 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1387 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1388 d
+= dinc
; //four_b_square * col;
1391 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1392 d
-= ddec
; //two_a_square * ((row << 1) - 3);
1397 PUTLINE ( left
, y1
, right
, y1
, FillBrushInst
);
1398 PUTLINE ( left
, y2
, right
, y2
, FillBrushInst
);
1402 if ( x1
> (left
+1) )
1404 PUTLINE ( left
, y1
, x1
, y1
, PenBrushInst
);
1405 PUTLINE ( x2
+1, y1
, right
, y1
, PenBrushInst
);
1406 PUTLINE ( left
+1, y2
, x1
, y2
, PenBrushInst
);
1407 PUTLINE ( x2
+1, y2
, right
+1, y2
, PenBrushInst
);
1411 PUTPIXEL ( left
, y1
, PenBrushInst
);
1412 PUTPIXEL ( right
, y2
, PenBrushInst
);
1419 y2
= bottom
-yradius
;
1423 for ( i
= y1
+1; i
< y2
; i
++ )
1424 PUTLINE ( left
, i
, right
, i
, FillBrushInst
);
1429 PUTLINE ( x1
, top
, x2
, top
, PenBrushInst
);
1430 PUTLINE ( right
, y1
, right
, y2
, PenBrushInst
);
1431 PUTLINE ( x2
, bottom
, x1
, bottom
, PenBrushInst
);
1432 PUTLINE ( left
, y2
, left
, y1
, PenBrushInst
);
1435 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1436 if (PenBrushObj
!= NULL
)
1437 PENOBJ_UnlockPen(PenBrushObj
);
1438 if (FillBrushObj
!= NULL
)
1439 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1455 DC
*dc
= DC_LockDc(hDC
);
1456 BOOL ret
= FALSE
; /* default to failure */
1458 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
1461 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
1462 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1464 else if (dc
->DC_Type
== DC_TYPE_INFO
)
1467 /* Yes, Windows really returns TRUE in this case */
1472 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
1488 BITMAPOBJ
*BitmapObj
;
1495 HPALETTE hDestPalette
;
1503 /* check parameters */
1504 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
1506 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
1508 for (i
= 0; i
< uMesh
; i
++, tr
++)
1510 if (tr
->Vertex1
>= uVertex
||
1511 tr
->Vertex2
>= uVertex
||
1512 tr
->Vertex3
>= uVertex
)
1514 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1521 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
1522 for (i
= 0; i
< uMesh
; i
++, rc
++)
1524 if (rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
1526 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1532 /* calculate extent */
1533 Extent
.left
= Extent
.right
= pVertex
->x
;
1534 Extent
.top
= Extent
.bottom
= pVertex
->y
;
1535 for (i
= 0; i
< uVertex
; i
++)
1537 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
1538 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
1539 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
1540 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
1543 DitherOrg
.x
= dc
->ptlDCOrig
.x
;
1544 DitherOrg
.y
= dc
->ptlDCOrig
.y
;
1545 Extent
.left
+= DitherOrg
.x
;
1546 Extent
.right
+= DitherOrg
.x
;
1547 Extent
.top
+= DitherOrg
.y
;
1548 Extent
.bottom
+= DitherOrg
.y
;
1550 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1551 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1554 hDestPalette
= BitmapObj
->hDIBPalette
;
1555 if (!hDestPalette
) hDestPalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
1557 PalDestGDI
= PALETTE_LockPalette(hDestPalette
);
1560 Mode
= PalDestGDI
->Mode
;
1561 PALETTE_UnlockPalette(PalDestGDI
);
1566 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(Mode
, PAL_RGB
, hDestPalette
, NULL
);
1569 Ret
= IntEngGradientFill(&BitmapObj
->SurfObj
,
1580 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1581 EngDeleteXlate(XlateObj
);
1598 PTRIVERTEX SafeVertex
;
1601 NTSTATUS Status
= STATUS_SUCCESS
;
1603 dc
= DC_LockDc(hdc
);
1606 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1609 if (dc
->DC_Type
== DC_TYPE_INFO
)
1612 /* Yes, Windows really returns TRUE in this case */
1615 if (!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
1618 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1624 case GRADIENT_FILL_RECT_H
:
1625 case GRADIENT_FILL_RECT_V
:
1626 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
1628 case GRADIENT_FILL_TRIANGLE
:
1629 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
1633 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1639 ProbeForRead(pVertex
,
1640 uVertex
* sizeof(TRIVERTEX
),
1648 Status
= _SEH_GetExceptionCode();
1652 if (!NT_SUCCESS(Status
))
1655 SetLastWin32Error(Status
);
1659 if (!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1662 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1666 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1670 /* pointers were already probed! */
1671 RtlCopyMemory(SafeVertex
,
1673 uVertex
* sizeof(TRIVERTEX
));
1674 RtlCopyMemory(SafeMesh
,
1680 Status
= _SEH_GetExceptionCode();
1684 if (!NT_SUCCESS(Status
))
1687 ExFreePool(SafeVertex
);
1688 SetLastNtError(Status
);
1692 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1695 ExFreePool(SafeVertex
);
1707 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1709 /* lie and say we succeded */