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->w.ROPmode));
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
39 &BrushInst.BrushObject, \
42 ROP2_TO_MIX(dc->w.ROPmode));
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 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
71 UnsafePoints
[CurrentPoint
].x
+= dc
->w
.DCOrgX
;
72 UnsafePoints
[CurrentPoint
].y
+= dc
->w
.DCOrgY
;
75 if (PATH_IsPathOpen(dc
->w
.path
))
76 ret
= PATH_Polygon(dc
, UnsafePoints
, Count
);
79 DestRect
.left
= UnsafePoints
[0].x
;
80 DestRect
.right
= UnsafePoints
[0].x
;
81 DestRect
.top
= UnsafePoints
[0].y
;
82 DestRect
.bottom
= UnsafePoints
[0].y
;
84 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
86 DestRect
.left
= min(DestRect
.left
, UnsafePoints
[CurrentPoint
].x
);
87 DestRect
.right
= max(DestRect
.right
, UnsafePoints
[CurrentPoint
].x
);
88 DestRect
.top
= min(DestRect
.top
, UnsafePoints
[CurrentPoint
].y
);
89 DestRect
.bottom
= max(DestRect
.bottom
, UnsafePoints
[CurrentPoint
].y
);
92 /* Now fill the polygon with the current brush. */
93 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
94 if (FillBrushObj
&& !(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
96 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
97 ret
= FillPolygon ( dc
, BitmapObj
, &FillBrushInst
.BrushObject
, ROP2_TO_MIX(dc
->w
.ROPmode
), UnsafePoints
, Count
, DestRect
);
99 BRUSHOBJ_UnlockBrush(FillBrushObj
);
101 /* get BRUSHOBJ from current pen. */
102 PenBrushObj
= PENOBJ_LockPen(dc
->w
.hPen
);
103 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
104 if (PenBrushObj
&& !(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
106 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
107 for ( CurrentPoint
= 0; CurrentPoint
< Count
; ++CurrentPoint
)
109 POINT To
, From
; //, Next;
111 /* Let CurrentPoint be i
112 * if i+1 > Count, Draw a line from Points[i] to Points[0]
113 * Draw a line from Points[i] to Points[i+1]
115 From
= UnsafePoints
[CurrentPoint
];
116 if (Count
<= CurrentPoint
+ 1)
117 To
= UnsafePoints
[0];
119 To
= UnsafePoints
[CurrentPoint
+ 1];
121 //DPRINT("Polygon Making line from (%d,%d) to (%d,%d)\n", From.x, From.y, To.x, To.y );
122 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
124 &PenBrushInst
.BrushObject
,
130 ROP2_TO_MIX(dc
->w
.ROPmode
)); /* MIX */
133 PENOBJ_UnlockPen(PenBrushObj
);
136 BITMAPOBJ_UnlockBitmap(BitmapObj
);
142 IntGdiPolyPolygon(DC
*dc
,
150 BOOL ret
= FALSE
; // default to failure
155 for (i
=0;i
<Count
;i
++)
157 ret
= IntGdiPolygon ( dc
, pt
, *pc
);
168 /******************************************************************************/
193 * This function uses optimized Bresenham's ellipse algorithm. It draws
194 * four lines of the ellipse in one pass.
197 * Make it look like a Windows ellipse.
211 int NewA
, NewB
, NewC
, NewD
;
213 int CenterX
, CenterY
;
214 int RadiusX
, RadiusY
;
216 PGDIBRUSHOBJ FillBrush
, PenBrush
;
217 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
218 BITMAPOBJ
*BitmapObj
;
221 BOOL ret
= TRUE
, Cond1
, Cond2
;
224 * Check the parameters.
227 if (nRightRect
<= nLeftRect
|| nBottomRect
<= nTopRect
)
229 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
234 * Get pointers to all necessary GDI objects.
240 SetLastWin32Error(ERROR_INVALID_HANDLE
);
246 /* Yes, Windows really returns TRUE in this case */
250 FillBrush
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
251 if (NULL
== FillBrush
)
254 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
258 PenBrush
= PENOBJ_LockPen(dc
->w
.hPen
);
259 if (NULL
== PenBrush
)
261 BRUSHOBJ_UnlockBrush(FillBrush
);
263 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
267 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
268 if (NULL
== BitmapObj
)
270 BRUSHOBJ_UnlockBrush(FillBrush
);
271 PENOBJ_UnlockPen(PenBrush
);
273 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
277 IntGdiInitBrushInstance(&FillBrushInst
, FillBrush
, dc
->XlateBrush
);
278 IntGdiInitBrushInstance(&PenBrushInst
, PenBrush
, dc
->XlatePen
);
280 nLeftRect
+= dc
->w
.DCOrgX
;
281 nRightRect
+= dc
->w
.DCOrgX
- 1;
282 nTopRect
+= dc
->w
.DCOrgY
;
283 nBottomRect
+= dc
->w
.DCOrgY
- 1;
285 RadiusX
= max((nRightRect
- nLeftRect
) >> 1, 1);
286 RadiusY
= max((nBottomRect
- nTopRect
) >> 1, 1);
287 CenterX
= nLeftRect
+ RadiusX
;
288 CenterY
= nTopRect
+ RadiusY
;
290 RectBounds
.left
= nLeftRect
;
291 RectBounds
.right
= nRightRect
;
292 RectBounds
.top
= nTopRect
;
293 RectBounds
.bottom
= nBottomRect
;
295 if (RadiusX
> RadiusY
)
311 NewB
= (iy
+ 32) >> 6;
313 NewD
= (NewB
* ny
) / nx
;
323 NewA
= (ix
+ 32) >> 6;
324 NewB
= (iy
+ 32) >> 6;
325 NewC
= (NewA
* ny
) / nx
;
326 NewD
= (NewB
* ny
) / nx
;
328 if (RadiusX
> RadiusY
)
330 Temp
= A
; A
= C
; C
= Temp
;
331 Temp
= B
; B
= D
; D
= Temp
;
332 Cond1
= ((C
!= NewA
) || (B
!= NewD
)) && (NewC
<= NewD
);
333 Cond2
= ((D
!= NewB
) || (A
!= NewC
)) && (NewC
<= B
);
337 Cond1
= ((C
!= NewC
) || (B
!= NewB
)) && (NewA
<= NewB
);
338 Cond2
= ((D
!= NewD
) || (A
!= NewA
)) && (NewA
<= B
);
342 * Draw the lines going from inner to outer (+ mirrored).
345 if ((A
> da
) && (A
< db
))
347 PUTLINE(CenterX
- D
, CenterY
+ A
, CenterX
+ D
, CenterY
+ A
, FillBrushInst
);
350 PUTLINE(CenterX
- D
, CenterY
- A
, CenterX
+ D
, CenterY
- A
, FillBrushInst
);
356 * Draw the lines going from outer to inner (+ mirrored).
359 if ((B
< db
) && (B
> da
))
361 PUTLINE(CenterX
- C
, CenterY
+ B
, CenterX
+ C
, CenterY
+ B
, FillBrushInst
);
362 PUTLINE(CenterX
- C
, CenterY
- B
, CenterX
+ C
, CenterY
- B
, FillBrushInst
);
367 * Draw the pixels on the margin.
372 PUTPIXEL(CenterX
+ C
, CenterY
+ B
, PenBrushInst
);
374 PUTPIXEL(CenterX
- C
, CenterY
+ B
, PenBrushInst
);
377 PUTPIXEL(CenterX
+ C
, CenterY
- B
, PenBrushInst
);
379 PUTPIXEL(CenterX
- C
, CenterY
- B
, PenBrushInst
);
385 PUTPIXEL(CenterX
+ D
, CenterY
+ A
, PenBrushInst
);
387 PUTPIXEL(CenterX
- D
, CenterY
+ A
, PenBrushInst
);
390 PUTPIXEL(CenterX
+ D
, CenterY
- A
, PenBrushInst
);
392 PUTPIXEL(CenterX
- D
, CenterY
- A
, PenBrushInst
);
397 BITMAPOBJ_UnlockBitmap(BitmapObj
);
398 BRUSHOBJ_UnlockBrush(FillBrush
);
399 PENOBJ_UnlockPen(PenBrush
);
405 typedef struct tagSHAPEPOINT
410 } SHAPEPOINT
, *PSHAPEPOINT
;
412 #define SHAPEPOINT_TYPE_CIRCLE 'C'
413 #define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
414 #define SHAPEPOINT_TYPE_LINE_LEFT 'L' /* Fill at left side of line */
416 #define SETPOINT(x, y, type) \
417 ShapePoints[*PointCount].X = (x); \
418 ShapePoints[*PointCount].Y = (y); \
419 ShapePoints[*PointCount].Type = (type); \
422 #define SETCIRCLEPOINT(x, y) \
423 SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
428 CirclePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
429 int Right
, int Bottom
)
431 int X
, X18
, X27
, X36
, X45
;
432 int Y
, Y14
, Y23
, Y58
, Y67
;
436 Even
= (0 == (Right
- Left
) % 2);
439 Radius
= (Right
- Left
) >> 1;
447 X27
= ((Left
+ Right
) >> 1) + 1;
448 X36
= (Left
+ Right
) >> 1;
452 Y58
= Top
+ Radius
+ 1;
453 Y67
= Top
+ (Right
- Left
);
454 ShapePoints
[*PointCount
].X
= X27
;
455 SETCIRCLEPOINT(X27
, Y23
);
456 SETCIRCLEPOINT(X36
, Y23
);
457 SETCIRCLEPOINT(X18
, Y14
);
458 SETCIRCLEPOINT(X45
, Y14
);
459 SETCIRCLEPOINT(X18
, Y58
);
460 SETCIRCLEPOINT(X45
, Y58
);
461 SETCIRCLEPOINT(X27
, Y67
);
462 SETCIRCLEPOINT(X36
, Y67
);
470 X27
= (Left
+ Right
) >> 1;
471 X36
= (Left
+ Right
) >> 1;
476 Y67
= Top
+ (Right
- Left
);
477 SETCIRCLEPOINT(X27
, Y23
);
478 SETCIRCLEPOINT(X45
, Y14
);
479 SETCIRCLEPOINT(X18
, Y58
);
480 SETCIRCLEPOINT(X27
, Y67
);
487 d
+= (X
<< 1) + (Even
? 4 : 3);
496 d
+= ((X
- Y
) << 1) + 5;
510 SETCIRCLEPOINT(X27
, Y23
);
511 SETCIRCLEPOINT(X36
, Y23
);
512 SETCIRCLEPOINT(X18
, Y14
);
513 SETCIRCLEPOINT(X45
, Y14
);
514 SETCIRCLEPOINT(X18
, Y58
);
515 SETCIRCLEPOINT(X45
, Y58
);
516 SETCIRCLEPOINT(X27
, Y67
);
517 SETCIRCLEPOINT(X36
, Y67
);
522 LinePoints(UINT
*PointCount
, PSHAPEPOINT ShapePoints
, int Left
, int Top
,
523 int Right
, int Bottom
, int XTo
, int YTo
, BOOL Start
)
525 LONG x
, y
, deltax
, deltay
, i
, xchange
, ychange
, error
;
528 x
= (Right
+ Left
) >> 1;
529 y
= (Bottom
+ Top
) >> 1;
549 Type
= (Start
? SHAPEPOINT_TYPE_LINE_LEFT
: SHAPEPOINT_TYPE_LINE_RIGHT
);
554 Type
= (Start
? SHAPEPOINT_TYPE_LINE_RIGHT
: SHAPEPOINT_TYPE_LINE_LEFT
);
559 for (i
= x
; i
<= XTo
; i
++)
561 SETPOINT(i
, y
, Type
);
566 for (i
= y
; i
<= YTo
; i
++)
568 SETPOINT(x
, i
, Type
);
577 for (i
= 0; i
< deltay
; i
++)
579 SETPOINT(x
, y
, Type
);
581 error
= error
+ deltax
;
586 error
= error
- deltay
;
592 for (i
= 0; i
< deltax
; i
++)
594 SETPOINT(x
, y
, Type
);
596 error
= error
+ deltay
;
600 error
= error
- deltax
;
609 CompareShapePoints(const void *pv1
, const void *pv2
)
611 if (((const PSHAPEPOINT
) pv1
)->Y
< ((const PSHAPEPOINT
) pv2
)->Y
)
615 else if (((const PSHAPEPOINT
) pv2
)->Y
< ((const PSHAPEPOINT
) pv1
)->Y
)
619 else if (((const PSHAPEPOINT
) pv1
)->X
< ((const PSHAPEPOINT
) pv2
)->X
)
623 else if (((const PSHAPEPOINT
) pv2
)->X
< ((const PSHAPEPOINT
) pv1
)->X
)
651 BRUSHOBJ PenBrushObj
;
652 PBRUSHOBJ FillBrushObj
;
653 PSHAPEPOINT ShapePoints
;
654 UINT Point
, PointCount
;
656 int Y
, CircleStart
, CircleEnd
, LineStart
, LineEnd
;
659 if (Right
<= Left
|| Bottom
<= Top
)
661 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
665 if (Right
- Left
!= Bottom
- Top
)
670 dc
= DC_LockDc ( hDC
);
673 SetLastWin32Error(ERROR_INVALID_HANDLE
);
679 /* Yes, Windows really returns TRUE in this case */
683 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
684 if (NULL
== FillBrushObj
)
687 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
691 Left
+= dc
->w
.DCOrgX
;
692 Right
+= dc
->w
.DCOrgX
;
694 Bottom
+= dc
->w
.DCOrgY
;
695 XRadialStart
+= dc
->w
.DCOrgX
;
696 YRadialStart
+= dc
->w
.DCOrgY
;
697 XRadialEnd
+= dc
->w
.DCOrgX
;
698 YRadialEnd
+= dc
->w
.DCOrgY
;
700 RectBounds
.left
= Left
;
701 RectBounds
.right
= Right
;
702 RectBounds
.top
= Top
;
703 RectBounds
.bottom
= Bottom
;
705 SurfObj
= (SURFOBJ
*) AccessUserObject((ULONG
)dc
->Surface
);
706 HPenToBrushObj(&PenBrushObj
, dc
->w
.hPen
);
708 /* Number of points for the circle is 4 * sqrt(2) * Radius, start
709 and end line have at most Radius points, so allocate at least
711 ShapePoints
= ExAllocatePoolWithTag(PagedPool
, 8 * (Right
- Left
+ 1) / 2 * sizeof(SHAPEPOINT
), TAG_SHAPE
);
712 if (NULL
== ShapePoints
)
714 BRUSHOBJ_UnlockBrush(FillBrushObj
);
717 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
723 PUTPIXEL(Left
, Top
, &PenBrushObj
);
724 BRUSHOBJ_UnlockBrush(FillBrushObj
);
731 CirclePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
);
732 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
733 XRadialStart
, YRadialStart
, TRUE
);
734 LinePoints(&PointCount
, ShapePoints
, Left
, Top
, Right
, Bottom
,
735 XRadialEnd
, YRadialEnd
, FALSE
);
736 ASSERT(PointCount
<= 8 * (Right
- Left
+ 1) / 2);
737 EngSort((PBYTE
) ShapePoints
, sizeof(SHAPEPOINT
), PointCount
, CompareShapePoints
);
741 while (Point
< PointCount
)
743 Y
= ShapePoints
[Point
].Y
;
745 /* Skip any line pixels before circle */
746 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
747 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
752 /* Handle left side of circle */
753 if (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
755 CircleStart
= ShapePoints
[Point
].X
;
757 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
758 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
759 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
763 CircleEnd
= ShapePoints
[Point
- 1].X
;
765 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
768 /* Handle line(s) (max 2) inside the circle */
769 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
770 && SHAPEPOINT_TYPE_CIRCLE
!= ShapePoints
[Point
].Type
)
772 LineStart
= ShapePoints
[Point
].X
;
774 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
775 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
776 && ShapePoints
[Point
].Type
== ShapePoints
[Point
- 1].Type
)
780 LineEnd
= ShapePoints
[Point
- 1].X
;
782 PUTLINE(LineStart
, Y
, LineEnd
+ 1, Y
, &PenBrushObj
);
785 /* Handle right side of circle */
786 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
787 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
789 CircleStart
= ShapePoints
[Point
].X
;
791 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
792 && ShapePoints
[Point
].X
== ShapePoints
[Point
- 1].X
+ 1
793 && SHAPEPOINT_TYPE_CIRCLE
== ShapePoints
[Point
].Type
)
797 CircleEnd
= ShapePoints
[Point
- 1].X
;
799 PUTLINE(CircleStart
, Y
, CircleEnd
+ 1, Y
, &PenBrushObj
);
802 /* Skip any line pixels after circle */
803 while (Point
< PointCount
&& ShapePoints
[Point
].Y
== Y
)
809 ExFreePool(ShapePoints
);
810 BRUSHOBJ_UnlockBrush(FillBrushObj
);
821 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
822 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
823 //first and second side, between the third and fourth side, and so on.
825 //WINDING Selects winding mode (fills any region with a nonzero winding value).
826 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
827 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
828 //The direction of each edge of the polygon is important.
830 extern BOOL
FillPolygon(PDC dc
,
842 NtGdiPolygon(HDC hDC
,
843 CONST PPOINT UnsafePoints
,
848 NTSTATUS Status
= STATUS_SUCCESS
;
853 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
859 ProbeForRead(UnsafePoints
,
860 Count
* sizeof(POINT
),
865 Status
= _SEH_GetExceptionCode();
869 if (!NT_SUCCESS(Status
))
871 SetLastNtError(Status
);
877 SetLastWin32Error(ERROR_INVALID_HANDLE
);
883 /* Yes, Windows really returns TRUE in this case */
886 Safept
= ExAllocatePoolWithTag(PagedPool
, sizeof(POINT
) * Count
, TAG_SHAPE
);
888 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
893 /* pointer was already probed! */
894 RtlCopyMemory(Safept
,
896 Count
* sizeof(POINT
));
900 Status
= _SEH_GetExceptionCode();
904 if(!NT_SUCCESS(Status
))
905 SetLastNtError(Status
);
907 Ret
= IntGdiPolygon(dc
, Safept
, Count
);
920 NtGdiPolyPolygon(HDC hDC
,
921 CONST LPPOINT Points
,
922 CONST LPINT PolyCounts
,
927 LPINT SafePolyPoints
;
928 NTSTATUS Status
= STATUS_SUCCESS
;
934 SetLastWin32Error(ERROR_INVALID_HANDLE
);
940 /* Yes, Windows really returns TRUE in this case */
949 Count
* sizeof(POINT
),
951 ProbeForRead(PolyCounts
,
957 Status
= _SEH_GetExceptionCode();
961 if (!NT_SUCCESS(Status
))
964 SetLastNtError(Status
);
968 Safept
= ExAllocatePoolWithTag(PagedPool
, (sizeof(POINT
) + sizeof(INT
)) * Count
, TAG_SHAPE
);
972 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
976 SafePolyPoints
= (LPINT
)&Safept
[Count
];
980 /* pointers already probed! */
981 RtlCopyMemory(Safept
,
983 Count
* sizeof(POINT
));
984 RtlCopyMemory(SafePolyPoints
,
986 Count
* sizeof(INT
));
990 Status
= _SEH_GetExceptionCode();
994 if(!NT_SUCCESS(Status
))
998 SetLastNtError(Status
);
1005 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1009 Ret
= IntGdiPolyPolygon(dc
, Safept
, SafePolyPoints
, Count
);
1019 IntRectangle(PDC dc
,
1025 BITMAPOBJ
*BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1026 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1027 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
1028 BOOL ret
= FALSE
; // default to failure
1032 ASSERT ( dc
); // caller's responsibility to set this up
1033 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1034 ASSERT ( BitmapObj
);
1036 if ( PATH_IsPathOpen(dc
->w
.path
) )
1038 ret
= PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1042 LeftRect
+= dc
->w
.DCOrgX
;
1043 RightRect
+= dc
->w
.DCOrgX
- 1;
1044 TopRect
+= dc
->w
.DCOrgY
;
1045 BottomRect
+= dc
->w
.DCOrgY
- 1;
1047 DestRect
.left
= LeftRect
;
1048 DestRect
.right
= RightRect
;
1049 DestRect
.top
= TopRect
;
1050 DestRect
.bottom
= BottomRect
;
1052 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
1056 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1058 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1059 ret
= IntEngBitBlt(&BitmapObj
->SurfObj
,
1067 &FillBrushInst
.BrushObject
,
1069 ROP3_TO_ROP4(PATCOPY
));
1073 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1075 /* get BRUSHOBJ from current pen. */
1076 PenBrushObj
= PENOBJ_LockPen(dc
->w
.hPen
);
1077 if (PenBrushObj
== NULL
)
1079 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1080 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1084 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1086 // Draw the rectangle with the current pen
1088 ret
= TRUE
; // change default to success
1090 if (!(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1092 Mix
= ROP2_TO_MIX(dc
->w
.ROPmode
);
1093 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1095 &PenBrushInst
.BrushObject
,
1096 LeftRect
, TopRect
, RightRect
, TopRect
,
1097 &DestRect
, // Bounding rectangle
1100 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1102 &PenBrushInst
.BrushObject
,
1103 RightRect
, TopRect
, RightRect
, BottomRect
,
1104 &DestRect
, // Bounding rectangle
1107 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1109 &PenBrushInst
.BrushObject
,
1110 RightRect
, BottomRect
, LeftRect
, BottomRect
,
1111 &DestRect
, // Bounding rectangle
1114 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
1116 &PenBrushInst
.BrushObject
,
1117 LeftRect
, BottomRect
, LeftRect
, TopRect
,
1118 &DestRect
, // Bounding rectangle
1122 PENOBJ_UnlockPen(PenBrushObj
);
1125 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1127 /* Move current position in DC?
1128 MSDN: The current position is neither used nor updated by Rectangle. */
1135 NtGdiRectangle(HDC hDC
,
1142 BOOL ret
; // default to failure
1144 dc
= DC_LockDc(hDC
);
1147 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1153 /* Yes, Windows really returns TRUE in this case */
1157 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
1175 BITMAPOBJ
*BitmapObj
;
1176 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
1177 GDIBRUSHINST FillBrushInst
, PenBrushInst
;
1179 int i
, col
, row
, width
, height
, x1
, x1start
, x2
, x2start
, y1
, y2
;
1180 int xradius
, yradius
;
1181 //float aspect_square;
1182 long a_square
, b_square
,
1183 two_a_square
, two_b_square
,
1184 four_a_square
, four_b_square
,
1187 ret
= TRUE
; // default to success
1189 ASSERT ( dc
); // caller's responsibility to set this up
1191 if ( PATH_IsPathOpen(dc
->w
.path
) )
1192 return PATH_RoundRect ( dc
, left
, top
, right
, bottom
,
1193 xCurveDiameter
, yCurveDiameter
);
1195 xradius
= xCurveDiameter
>> 1;
1196 yradius
= yCurveDiameter
>> 1;
1198 left
+= dc
->w
.DCOrgX
;
1199 right
+= dc
->w
.DCOrgX
;
1200 top
+= dc
->w
.DCOrgY
;
1201 bottom
+= dc
->w
.DCOrgY
;
1203 RectBounds
.left
= left
;
1204 RectBounds
.right
= right
;
1205 RectBounds
.top
= top
;
1206 RectBounds
.bottom
= bottom
;
1208 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1211 /* Nothing to do, as we don't have a bitmap */
1212 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
1216 FillBrushObj
= BRUSHOBJ_LockBrush(dc
->w
.hBrush
);
1219 if (FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1221 /* make null brush check simpler... */
1222 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1223 FillBrushObj
= NULL
;
1227 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1231 PenBrushObj
= PENOBJ_LockPen(dc
->w
.hPen
);
1234 if (PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
)
1236 /* make null pen check simpler... */
1237 PENOBJ_UnlockPen(PenBrushObj
);
1242 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
1249 width
= right
- left
;
1250 height
= bottom
- top
;
1252 if ( (xradius
<<1) > width
)
1253 xradius
= width
>> 1;
1254 if ( (yradius
<<1) > height
)
1255 yradius
= height
>> 1;
1257 b_square
= yradius
* yradius
;
1258 a_square
= xradius
* xradius
;
1261 two_a_square
= a_square
<< 1;
1262 four_a_square
= a_square
<< 2;
1263 four_b_square
= b_square
<< 2;
1264 two_b_square
= b_square
<< 1;
1265 d
= two_a_square
* ((row
- 1) * (row
))
1267 + two_b_square
* (1 - a_square
);
1277 dinc
= two_b_square
*3; /* two_b_square * (3 + (col << 1)); */
1278 ddec
= four_a_square
* row
;
1286 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1293 PUTLINE ( x1
, y1
, x1start
, y1
, PenBrushInst
);
1294 PUTLINE ( x2start
+1, y2
, x2
+1, y2
, PenBrushInst
);
1298 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1299 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1307 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1310 if ( x1start
>= x1
)
1312 PUTLINE ( x1
, y1
, x1start
+1, y1
, PenBrushInst
);
1313 PUTLINE ( x2start
, y2
, x2
+1, y2
, PenBrushInst
);
1317 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1318 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1326 PUTLINE ( x1
, y2
, x1start
+1, y2
, PenBrushInst
);
1327 PUTLINE ( x2start
, y1
, x2
+1, y1
, PenBrushInst
);
1331 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1332 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1337 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1341 int potential_steps
= ( a_square
* row
) / b_square
- col
+ 1;
1342 while ( d
< 0 && potential_steps
-- )
1344 d
+= dinc
; /* two_b_square * (3 + (col << 1)); */
1345 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1348 if ( a_square
* row
<= b_square
* col
)
1352 d
= two_b_square
* (col
+ 1) * col
1353 + two_a_square
* (row
* (row
- 2) + 1)
1354 + (1 - two_a_square
) * b_square
;
1355 dinc
= ddec
; /* four_b_square * col; */
1356 ddec
= two_a_square
* ((row
<< 1) - 3);
1362 PUTLINE ( x1
, y1
, x2
, y1
, FillBrushInst
);
1363 PUTLINE ( x1
, y2
, x2
, y2
, FillBrushInst
);
1367 PUTPIXEL ( x2
, y1
, PenBrushInst
);
1368 PUTPIXEL ( x1
, y2
, PenBrushInst
);
1369 PUTPIXEL ( x2
, y2
, PenBrushInst
);
1370 PUTPIXEL ( x1
, y1
, PenBrushInst
);
1375 col
++, x1
--, x2
++, dinc
+= four_b_square
;
1376 d
+= dinc
; //four_b_square * col;
1379 row
--, y1
++, y2
--, ddec
-= four_a_square
;
1380 d
-= ddec
; //two_a_square * ((row << 1) - 3);
1385 PUTLINE ( left
, y1
, right
, y1
, FillBrushInst
);
1386 PUTLINE ( left
, y2
, right
, y2
, FillBrushInst
);
1390 if ( x1
> (left
+1) )
1392 PUTLINE ( left
, y1
, x1
, y1
, PenBrushInst
);
1393 PUTLINE ( x2
+1, y1
, right
, y1
, PenBrushInst
);
1394 PUTLINE ( left
+1, y2
, x1
, y2
, PenBrushInst
);
1395 PUTLINE ( x2
+1, y2
, right
+1, y2
, PenBrushInst
);
1399 PUTPIXEL ( left
, y1
, PenBrushInst
);
1400 PUTPIXEL ( right
, y2
, PenBrushInst
);
1407 y2
= bottom
-yradius
;
1411 for ( i
= y1
+1; i
< y2
; i
++ )
1412 PUTLINE ( left
, i
, right
, i
, FillBrushInst
);
1417 PUTLINE ( x1
, top
, x2
, top
, PenBrushInst
);
1418 PUTLINE ( right
, y1
, right
, y2
, PenBrushInst
);
1419 PUTLINE ( x2
, bottom
, x1
, bottom
, PenBrushInst
);
1420 PUTLINE ( left
, y2
, left
, y1
, PenBrushInst
);
1423 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1424 if(PenBrushObj
!= NULL
)
1425 PENOBJ_UnlockPen(PenBrushObj
);
1426 if(FillBrushObj
!= NULL
)
1427 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1443 DC
*dc
= DC_LockDc(hDC
);
1444 BOOL ret
= FALSE
; /* default to failure */
1446 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
1449 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
1450 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1455 /* Yes, Windows really returns TRUE in this case */
1460 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
1476 BITMAPOBJ
*BitmapObj
;
1490 /* check parameters */
1491 if(ulMode
& GRADIENT_FILL_TRIANGLE
)
1493 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
1495 for(i
= 0; i
< uMesh
; i
++, tr
++)
1497 if(tr
->Vertex1
>= uVertex
||
1498 tr
->Vertex2
>= uVertex
||
1499 tr
->Vertex3
>= uVertex
)
1501 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1508 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
1509 for(i
= 0; i
< uMesh
; i
++, rc
++)
1511 if(rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
1513 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1519 /* calculate extent */
1520 Extent
.left
= Extent
.right
= pVertex
->x
;
1521 Extent
.top
= Extent
.bottom
= pVertex
->y
;
1522 for(i
= 0; i
< uVertex
; i
++)
1524 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
1525 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
1526 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
1527 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
1530 DitherOrg
.x
= dc
->w
.DCOrgX
;
1531 DitherOrg
.y
= dc
->w
.DCOrgY
;
1532 Extent
.left
+= DitherOrg
.x
;
1533 Extent
.right
+= DitherOrg
.x
;
1534 Extent
.top
+= DitherOrg
.y
;
1535 Extent
.bottom
+= DitherOrg
.y
;
1537 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1538 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
1541 PalDestGDI
= PALETTE_LockPalette(dc
->w
.hPalette
);
1542 /* FIXME - PalDestGDI can be NULL!!! Don't assert but handle this case gracefully! */
1544 Mode
= PalDestGDI
->Mode
;
1545 PALETTE_UnlockPalette(PalDestGDI
);
1547 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(Mode
, PAL_RGB
, dc
->w
.hPalette
, NULL
);
1550 Ret
= IntEngGradientFill(&BitmapObj
->SurfObj
,
1561 BITMAPOBJ_UnlockBitmap(BitmapObj
);
1562 EngDeleteXlate(XlateObj
);
1579 PTRIVERTEX SafeVertex
;
1582 NTSTATUS Status
= STATUS_SUCCESS
;
1584 dc
= DC_LockDc(hdc
);
1587 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1593 /* Yes, Windows really returns TRUE in this case */
1596 if(!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
1599 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1605 case GRADIENT_FILL_RECT_H
:
1606 case GRADIENT_FILL_RECT_V
:
1607 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
1609 case GRADIENT_FILL_TRIANGLE
:
1610 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
1614 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1620 ProbeForRead(pVertex
,
1621 uVertex
* sizeof(TRIVERTEX
),
1629 Status
= _SEH_GetExceptionCode();
1633 if (!NT_SUCCESS(Status
))
1636 SetLastWin32Error(Status
);
1640 if(!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1643 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1647 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1651 /* pointers were already probed! */
1652 RtlCopyMemory(SafeVertex
,
1654 uVertex
* sizeof(TRIVERTEX
));
1655 RtlCopyMemory(SafeMesh
,
1661 Status
= _SEH_GetExceptionCode();
1665 if(!NT_SUCCESS(Status
))
1668 ExFreePool(SafeVertex
);
1669 SetLastNtError(Status
);
1673 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1676 ExFreePool(SafeVertex
);