2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/fillshap.c
14 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
15 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
23 PBRUSH pbrLine
, pbrFill
;
24 BOOL ret
= FALSE
; // Default to failure
32 ASSERT(dc
); // Caller's responsibility to pass a valid dc
34 if (!Points
|| Count
< 2 )
36 EngSetLastError(ERROR_INVALID_PARAMETER
);
44 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
45 Left = min(Left, Points[CurrentPoint].x);
46 Top = min(Top, Points[CurrentPoint].y);
50 pdcattr
= dc
->pdcattr
;
52 /* Convert to screen coordinates */
53 IntLPtoDP(dc
, Points
, Count
);
54 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
56 Points
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
57 Points
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
59 // No need to have path here.
61 DestRect
.left
= Points
[0].x
;
62 DestRect
.right
= Points
[0].x
;
63 DestRect
.top
= Points
[0].y
;
64 DestRect
.bottom
= Points
[0].y
;
66 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
68 DestRect
.left
= min(DestRect
.left
, Points
[CurrentPoint
].x
);
69 DestRect
.right
= max(DestRect
.right
, Points
[CurrentPoint
].x
);
70 DestRect
.top
= min(DestRect
.top
, Points
[CurrentPoint
].y
);
71 DestRect
.bottom
= max(DestRect
.bottom
, Points
[CurrentPoint
].y
);
74 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
75 DC_vUpdateFillBrush(dc
);
77 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
78 DC_vUpdateLineBrush(dc
);
80 /* Special locking order to avoid lock-ups */
81 pbrFill
= dc
->dclevel
.pbrFill
;
82 pbrLine
= dc
->dclevel
.pbrLine
;
83 psurf
= dc
->dclevel
.pSurface
;
86 /* Memory DC without a bitmap selected, nothing to do. */
90 /* Now fill the polygon with the current fill brush. */
91 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
93 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
94 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
95 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
96 ret
= IntFillPolygon (dc
,
98 &dc
->eboFill
.BrushObject
,
105 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
106 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
110 for (i
= 0; i
< Count
-1; i
++)
113 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
114 // Points[0].x, Points[0].y,
115 // Points[1].x, Points[1].y );
117 ret
= IntEngLineTo(&psurf
->SurfObj
,
119 &dc
->eboLine
.BrushObject
,
120 Points
[i
].x
, /* From */
122 Points
[i
+1].x
, /* To */
125 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
128 /* Close the polygon */
131 ret
= IntEngLineTo(&psurf
->SurfObj
,
133 &dc
->eboLine
.BrushObject
,
134 Points
[Count
-1].x
, /* From */
136 Points
[0].x
, /* To */
139 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
148 IntGdiPolyPolygon(DC
*dc
,
153 if (PATH_IsPathOpen(dc
->dclevel
))
154 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
158 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
160 Points
+=*PolyCounts
++;
166 IntPolygon(HDC hdc
, POINT
*Point
, int Count
)
171 pdc
= DC_LockDc(hdc
);
174 EngSetLastError(ERROR_INVALID_HANDLE
);
178 bResult
= IntGdiPolygon(pdc
, Point
, Count
);
185 /******************************************************************************/
194 * This function uses optimized Bresenham's ellipse algorithm. It draws
195 * four lines of the ellipse in one pass.
212 LONG PenWidth
, PenOrigWidth
;
213 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
214 PBRUSH pFillBrushObj
;
215 BRUSH tmpFillBrushObj
;
220 EngSetLastError(ERROR_INVALID_HANDLE
);
224 if (PATH_IsPathOpen(dc
->dclevel
))
226 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
232 //// Could this use PATH_CheckCorners ?
234 if ((Left
== Right
) || (Top
== Bottom
))
242 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
246 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
250 pdcattr
= dc
->pdcattr
;
252 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
253 DC_vUpdateFillBrush(dc
);
255 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
256 DC_vUpdateLineBrush(dc
);
258 pbrush
= PEN_ShareLockPen(pdcattr
->hpen
);
261 DPRINT1("Ellipse Fail 1\n");
263 EngSetLastError(ERROR_INTERNAL_ERROR
);
267 PenOrigWidth
= PenWidth
= pbrush
->lWidth
;
268 if (pbrush
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
270 if (pbrush
->ulPenStyle
== PS_INSIDEFRAME
)
272 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
273 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
274 Left
+= PenWidth
/ 2;
275 Right
-= (PenWidth
- 1) / 2;
277 Bottom
-= (PenWidth
- 1) / 2;
280 if (!PenWidth
) PenWidth
= 1;
281 pbrush
->lWidth
= PenWidth
;
283 RectBounds
.left
= Left
;
284 RectBounds
.right
= Right
;
285 RectBounds
.top
= Top
;
286 RectBounds
.bottom
= Bottom
;
288 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
290 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
291 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
292 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
293 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
295 // Setup for dynamic width and height.
296 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
297 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
298 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
299 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
301 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
302 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
304 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
305 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
307 pFillBrushObj
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
308 if (NULL
== pFillBrushObj
)
310 DPRINT1("FillEllipse Fail\n");
311 EngSetLastError(ERROR_INTERNAL_ERROR
);
316 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
317 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
318 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
319 tmpFillBrushObj
.ptOrigin
.x
+= dc
->ptlDCOrig
.x
;
320 tmpFillBrushObj
.ptOrigin
.y
+= dc
->ptlDCOrig
.y
;
322 DC_vPrepareDCsForBlit(dc
, &RectBounds
, NULL
, NULL
);
324 ret
= IntFillEllipse( dc
,
330 BRUSH_ShareUnlockBrush(pFillBrushObj
);
334 ret
= IntDrawEllipse( dc
,
342 DC_vFinishBlit(dc
, NULL
);
345 pbrush
->lWidth
= PenOrigWidth
;
346 PEN_ShareUnlockPen(pbrush
);
348 DPRINT("Ellipse Exit.\n");
354 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
355 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
356 // first and second side, between the third and fourth side, and so on.
358 // WINDING Selects winding mode (fills any region with a nonzero winding value).
359 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
360 // This value is defined as the number of times a pen used to draw the polygon would go around the region.
361 // The direction of each edge of the polygon is important.
363 extern BOOL
FillPolygon(PDC dc
,
376 NtGdiPolyPolyDraw( IN HDC hDC
,
377 IN PPOINT UnsafePoints
,
378 IN PULONG UnsafeCounts
,
388 ULONG nPoints
= 0, nMaxPoints
= 0, i
;
390 /* Validate parameters */
391 if ((UnsafePoints
== NULL
) ||
392 (UnsafeCounts
== NULL
) ||
394 (Count
> ULONG_MAX
/ sizeof(ULONG
)) ||
396 (iFunc
> GdiPolyPolyRgn
))
398 DPRINT1("NtGdiPolyPolyDraw - Invalid parameter!\n");
399 /* Windows doesn't set last error */
405 /* Probe the buffer of counts for each polygon */
406 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
408 /* Count points. Note: We are not copying the buffer, so it can be
409 changed by usermode. This is ok, since the content is validated
411 for (i
= 0; i
< Count
; i
++)
413 Status
= RtlULongAdd(nMaxPoints
, UnsafeCounts
[i
], &nMaxPoints
);
414 if (!NT_SUCCESS(Status
))
416 DPRINT1("Overflow when counting points!\n");
421 ProbeForRead(UnsafePoints
, nMaxPoints
* sizeof(POINT
), 1);
423 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
425 DPRINT1("Got exception!\n");
426 /* Windows doesn't set last error */
433 /* If all polygon counts are zero, return FALSE
434 without setting a last error code. */
435 DPRINT1("nMaxPoints == 0!\n");
439 /* Allocate one buffer for both counts and points */
440 pTemp
= ExAllocatePoolWithTag(PagedPool
,
441 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
445 DPRINT1("Failed to allocate %lu bytes (Count = %lu, nPoints = %u).\n",
446 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
449 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
454 SafePoints
= (PPOINT
)&SafeCounts
[Count
];
458 /* Pointers already probed! */
459 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
460 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
462 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
464 DPRINT1("Got exception!\n");
465 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
470 /* Now that the buffers are copied, validate them again */
471 for (i
= 0; i
< Count
; i
++)
473 /* If any poly count is 0 or 1, fail */
474 if (SafeCounts
[i
] < 2)
476 DPRINT1("Invalid: UnsafeCounts[%lu] == %lu\n", i
, SafeCounts
[i
]);
477 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
478 EngSetLastError(ERROR_INVALID_PARAMETER
);
482 Status
= RtlULongAdd(nPoints
, SafeCounts
[i
], &nPoints
);
483 if (!NT_SUCCESS(Status
))
485 DPRINT1("Overflow when counting points!\n");
490 /* If the 2nd count does not match the 1st, someone changed the buffer
492 if (nPoints
!= nMaxPoints
)
494 DPRINT1("Polygon count mismatch: %lu != %lu\n", nPoints
, nMaxPoints
);
495 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
499 /* Special handling for GdiPolyPolyRgn */
500 if (iFunc
== GdiPolyPolyRgn
)
502 INT iMode
= (INT
)(UINT_PTR
)hDC
;
505 hrgn
= GreCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, iMode
);
507 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
508 return (ULONG_PTR
)hrgn
;
514 EngSetLastError(ERROR_INVALID_HANDLE
);
515 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
519 DC_vPrepareDCsForBlit(dc
, NULL
, NULL
, NULL
);
521 if (dc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
522 DC_vUpdateFillBrush(dc
);
524 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
525 DC_vUpdateLineBrush(dc
);
527 /* Perform the actual work */
531 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
533 case GdiPolyPolyLine
:
534 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
537 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
540 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
542 case GdiPolyBezierTo
:
543 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
546 EngSetLastError(ERROR_INVALID_PARAMETER
);
550 /* Cleanup and return */
551 DC_vFinishBlit(dc
, NULL
);
553 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
555 return (ULONG_PTR
)Ret
;
567 SURFACE
*psurf
= NULL
;
568 PBRUSH pbrLine
, pbrFill
;
569 BOOL ret
= FALSE
; // Default to failure
575 ASSERT ( dc
); // Caller's responsibility to set this up
577 pdcattr
= dc
->pdcattr
;
579 // Rectangle Path only.
580 if ( PATH_IsPathOpen(dc
->dclevel
) )
582 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
585 /* Make sure rectangle is not inverted */
586 DestRect
.left
= min(LeftRect
, RightRect
);
587 DestRect
.right
= max(LeftRect
, RightRect
);
588 DestRect
.top
= min(TopRect
, BottomRect
);
589 DestRect
.bottom
= max(TopRect
, BottomRect
);
591 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
593 DestRect
.left
+= dc
->ptlDCOrig
.x
;
594 DestRect
.right
+= dc
->ptlDCOrig
.x
;
595 DestRect
.top
+= dc
->ptlDCOrig
.y
;
596 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
598 if (dc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
600 IntUpdateBoundsRect(dc
, &DestRect
);
603 /* In GM_COMPATIBLE, don't include bottom and right edges */
604 if (pdcattr
->iGraphicsMode
== GM_COMPATIBLE
)
610 DC_vPrepareDCsForBlit(dc
, &DestRect
, NULL
, NULL
);
612 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
613 DC_vUpdateFillBrush(dc
);
615 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
616 DC_vUpdateLineBrush(dc
);
618 pbrFill
= dc
->dclevel
.pbrFill
;
619 pbrLine
= dc
->dclevel
.pbrLine
;
626 psurf
= dc
->dclevel
.pSurface
;
635 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
637 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
638 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
639 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
640 ret
= IntEngBitBlt(&psurf
->SurfObj
,
648 &dc
->eboFill
.BrushObject
,
650 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY
));
654 // Draw the rectangle with the current pen
656 ret
= TRUE
; // Change default to success
658 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
660 Mix
= ROP2_TO_MIX(pdcattr
->jROP2
);
661 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
663 &dc
->eboLine
.BrushObject
,
664 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
665 &DestRect
, // Bounding rectangle
668 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
670 &dc
->eboLine
.BrushObject
,
671 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
672 &DestRect
, // Bounding rectangle
675 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
677 &dc
->eboLine
.BrushObject
,
678 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
679 &DestRect
, // Bounding rectangle
682 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
684 &dc
->eboLine
.BrushObject
,
685 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
686 &DestRect
, // Bounding rectangle
691 DC_vFinishBlit(dc
, NULL
);
693 /* Move current position in DC?
694 MSDN: The current position is neither used nor updated by Rectangle. */
701 NtGdiRectangle(HDC hDC
,
708 BOOL ret
; // Default to failure
713 EngSetLastError(ERROR_INVALID_HANDLE
);
717 /* Do we rotate or shear? */
718 if (!(dc
->pdcattr
->mxWorldToDevice
.flAccel
& XFORM_SCALE
))
720 POINTL DestCoords
[4];
721 ULONG PolyCounts
= 4;
723 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
724 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
725 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
726 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
727 // Use IntGdiPolyPolygon so to support PATH.
728 ret
= IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
732 ret
= IntRectangle(dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
753 PBRUSH pbrLine
, pbrFill
;
755 LONG PenWidth
, PenOrigWidth
;
756 BOOL ret
= TRUE
; // Default to success
759 ASSERT ( dc
); // Caller's responsibility to set this up
761 if ( PATH_IsPathOpen(dc
->dclevel
) )
762 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
763 xCurveDiameter
, yCurveDiameter
);
765 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
767 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
768 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
772 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
776 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
779 pdcattr
= dc
->pdcattr
;
781 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
782 DC_vUpdateFillBrush(dc
);
784 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
785 DC_vUpdateLineBrush(dc
);
787 pbrLine
= PEN_ShareLockPen(pdcattr
->hpen
);
790 /* Nothing to do, as we don't have a bitmap */
791 EngSetLastError(ERROR_INTERNAL_ERROR
);
795 PenOrigWidth
= PenWidth
= pbrLine
->lWidth
;
796 if (pbrLine
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
798 if (pbrLine
->ulPenStyle
== PS_INSIDEFRAME
)
800 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
801 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
802 Left
+= PenWidth
/ 2;
803 Right
-= (PenWidth
- 1) / 2;
805 Bottom
-= (PenWidth
- 1) / 2;
808 if (!PenWidth
) PenWidth
= 1;
809 pbrLine
->lWidth
= PenWidth
;
811 RectBounds
.left
= Left
;
812 RectBounds
.top
= Top
;
813 RectBounds
.right
= Right
;
814 RectBounds
.bottom
= Bottom
;
816 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
818 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
819 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
820 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
821 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
823 pbrFill
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
826 DPRINT1("FillRound Fail\n");
827 EngSetLastError(ERROR_INTERNAL_ERROR
);
833 DC_vPrepareDCsForBlit(dc
, &RectBounds
, NULL
, NULL
);
835 RtlCopyMemory(&brushTemp
, pbrFill
, sizeof(brushTemp
));
836 brushTemp
.ptOrigin
.x
+= RectBounds
.left
- Left
;
837 brushTemp
.ptOrigin
.y
+= RectBounds
.top
- Top
;
838 ret
= IntFillRoundRect( dc
,
846 BRUSH_ShareUnlockBrush(pbrFill
);
850 ret
= IntDrawRoundRect( dc
,
860 DC_vFinishBlit(dc
, NULL
);
864 pbrLine
->lWidth
= PenOrigWidth
;
865 PEN_ShareUnlockPen(pbrLine
);
880 DC
*dc
= DC_LockDc(hDC
);
881 BOOL ret
= FALSE
; /* Default to failure */
883 DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
886 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
887 EngSetLastError(ERROR_INVALID_HANDLE
);
891 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
916 /* Check parameters */
917 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
919 PGRADIENT_TRIANGLE pTriangle
= (PGRADIENT_TRIANGLE
)pMesh
;
921 for (i
= 0; i
< nMesh
; i
++, pTriangle
++)
923 if (pTriangle
->Vertex1
>= nVertex
||
924 pTriangle
->Vertex2
>= nVertex
||
925 pTriangle
->Vertex3
>= nVertex
)
927 EngSetLastError(ERROR_INVALID_PARAMETER
);
934 PGRADIENT_RECT pRect
= (PGRADIENT_RECT
)pMesh
;
935 for (i
= 0; i
< nMesh
; i
++, pRect
++)
937 if (pRect
->UpperLeft
>= nVertex
|| pRect
->LowerRight
>= nVertex
)
939 EngSetLastError(ERROR_INVALID_PARAMETER
);
945 /* Lock the output DC */
946 pdc
= DC_LockDc(hdc
);
949 EngSetLastError(ERROR_INVALID_HANDLE
);
953 if (!pdc
->dclevel
.pSurface
)
955 /* Memory DC with no surface selected */
957 return TRUE
; // CHECKME
960 /* Calculate extent */
961 rclExtent
.left
= rclExtent
.right
= pVertex
->x
;
962 rclExtent
.top
= rclExtent
.bottom
= pVertex
->y
;
963 for (i
= 0; i
< nVertex
; i
++)
965 rclExtent
.left
= min(rclExtent
.left
, (pVertex
+ i
)->x
);
966 rclExtent
.right
= max(rclExtent
.right
, (pVertex
+ i
)->x
);
967 rclExtent
.top
= min(rclExtent
.top
, (pVertex
+ i
)->y
);
968 rclExtent
.bottom
= max(rclExtent
.bottom
, (pVertex
+ i
)->y
);
970 IntLPtoDP(pdc
, (LPPOINT
)&rclExtent
, 2);
972 rclExtent
.left
+= pdc
->ptlDCOrig
.x
;
973 rclExtent
.right
+= pdc
->ptlDCOrig
.x
;
974 rclExtent
.top
+= pdc
->ptlDCOrig
.y
;
975 rclExtent
.bottom
+= pdc
->ptlDCOrig
.y
;
977 ptlDitherOrg
.x
= ptlDitherOrg
.y
= 0;
978 IntLPtoDP(pdc
, (LPPOINT
)&ptlDitherOrg
, 1);
980 ptlDitherOrg
.x
+= pdc
->ptlDCOrig
.x
;
981 ptlDitherOrg
.y
+= pdc
->ptlDCOrig
.y
;
983 if (pdc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
985 IntUpdateBoundsRect(pdc
, &rclExtent
);
988 DC_vPrepareDCsForBlit(pdc
, &rclExtent
, NULL
, NULL
);
990 psurf
= pdc
->dclevel
.pSurface
;
992 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0, 0);
994 bRet
= IntEngGradientFill(&psurf
->SurfObj
,
1005 EXLATEOBJ_vCleanup(&exlo
);
1006 DC_vFinishBlit(pdc
, NULL
);
1023 PTRIVERTEX SafeVertex
;
1025 ULONG cbVertex
, cbMesh
;
1027 /* Validate parameters */
1028 if (!pVertex
|| !nVertex
|| !pMesh
|| !nMesh
)
1030 EngSetLastError(ERROR_INVALID_PARAMETER
);
1036 case GRADIENT_FILL_RECT_H
:
1037 case GRADIENT_FILL_RECT_V
:
1038 cbMesh
= nMesh
* sizeof(GRADIENT_RECT
);
1040 case GRADIENT_FILL_TRIANGLE
:
1041 cbMesh
= nMesh
* sizeof(GRADIENT_TRIANGLE
);
1044 EngSetLastError(ERROR_INVALID_PARAMETER
);
1048 cbVertex
= nVertex
* sizeof(TRIVERTEX
) ;
1049 if(cbVertex
+ cbMesh
<= cbVertex
)
1055 /* Allocate a kernel mode buffer */
1056 SafeVertex
= ExAllocatePoolWithTag(PagedPool
, cbVertex
+ cbMesh
, TAG_SHAPE
);
1059 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1063 SafeMesh
= (PVOID
)((ULONG_PTR
)SafeVertex
+ cbVertex
);
1065 /* Copy the parameters to kernel mode */
1068 ProbeForRead(pVertex
, cbVertex
, 1);
1069 ProbeForRead(pMesh
, cbMesh
, 1);
1070 RtlCopyMemory(SafeVertex
, pVertex
, cbVertex
);
1071 RtlCopyMemory(SafeMesh
, pMesh
, cbMesh
);
1073 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1075 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1076 SetLastNtError(_SEH2_GetExceptionCode());
1077 _SEH2_YIELD(return FALSE
;)
1081 /* Call the internal function */
1082 bRet
= GreGradientFill(hdc
, SafeVertex
, nVertex
, SafeMesh
, nMesh
, ulMode
);
1084 /* Cleanup and return result */
1085 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1108 dc
= DC_LockDc(hDC
);
1111 EngSetLastError(ERROR_INVALID_HANDLE
);
1115 if (!dc
->dclevel
.pSurface
)
1122 pdcattr
= dc
->pdcattr
;
1127 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1129 DC_vPrepareDCsForBlit(dc
, &DestRect
, NULL
, NULL
);
1131 /// FIXME: what about prgnVIS? And what about REAL clipping?
1132 psurf
= dc
->dclevel
.pSurface
;
1135 Ret
= REGION_PtInRegion(dc
->prgnRao
, Pt
.x
, Pt
.y
);
1137 REGION_GetRgnBox(dc
->prgnRao
, (LPRECT
)&DestRect
);
1140 DC_vFinishBlit(dc
, NULL
);
1146 RECTL_vSetRect(&DestRect
, 0, 0, psurf
->SurfObj
.sizlBitmap
.cx
, psurf
->SurfObj
.sizlBitmap
.cy
);
1149 if (dc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
1151 IntUpdateBoundsRect(dc
, &DestRect
);
1154 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0xffffff, 0);
1156 /* Only solid fills supported for now
1157 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1158 * Version a (most likely slow): call DrvPatBlt for every pixel
1159 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1160 ConvColor
= XLATEOBJ_iXlate(&exlo
.xlo
, Color
);
1161 Ret
= DIB_XXBPP_FloodFillSolid(&psurf
->SurfObj
, &dc
->eboFill
.BrushObject
, &DestRect
, &Pt
, ConvColor
, FillType
);
1163 DC_vFinishBlit(dc
, NULL
);
1165 EXLATEOBJ_vCleanup(&exlo
);