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
33 ASSERT(dc
); // Caller's responsibility to pass a valid dc
35 if (!Points
|| Count
< 2 )
37 EngSetLastError(ERROR_INVALID_PARAMETER
);
45 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
46 Left = min(Left, Points[CurrentPoint].x);
47 Top = min(Top, Points[CurrentPoint].y);
51 pdcattr
= dc
->pdcattr
;
53 /* Convert to screen coordinates */
54 IntLPtoDP(dc
, Points
, Count
);
55 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
57 Points
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
58 Points
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
60 // No need to have path here.
62 DestRect
.left
= Points
[0].x
;
63 DestRect
.right
= Points
[0].x
;
64 DestRect
.top
= Points
[0].y
;
65 DestRect
.bottom
= Points
[0].y
;
67 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
69 DestRect
.left
= min(DestRect
.left
, Points
[CurrentPoint
].x
);
70 DestRect
.right
= max(DestRect
.right
, Points
[CurrentPoint
].x
);
71 DestRect
.top
= min(DestRect
.top
, Points
[CurrentPoint
].y
);
72 DestRect
.bottom
= max(DestRect
.bottom
, Points
[CurrentPoint
].y
);
75 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
76 DC_vUpdateFillBrush(dc
);
78 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
79 DC_vUpdateLineBrush(dc
);
81 /* Special locking order to avoid lock-ups */
82 pbrFill
= dc
->dclevel
.pbrFill
;
83 pbrLine
= dc
->dclevel
.pbrLine
;
84 psurf
= dc
->dclevel
.pSurface
;
87 /* Memory DC without a bitmap selected, nothing to do. */
91 /* Now fill the polygon with the current fill brush. */
92 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
94 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
95 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
96 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
97 ret
= IntFillPolygon (dc
,
99 &dc
->eboFill
.BrushObject
,
106 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
107 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
109 if (IntIsEffectiveWidePen(pbrLine
))
112 PATH_Delete(dc
->dclevel
.hPath
);
113 dc
->dclevel
.hPath
= NULL
;
116 pPath
= PATH_CreatePath(Count
+ 1);
117 dc
->dclevel
.flPath
|= DCPATH_ACTIVE
;
118 dc
->dclevel
.hPath
= pPath
->BaseObject
.hHmgr
;
119 pPath
->pos
= Points
[0];
120 IntLPtoDP(dc
, &pPath
->pos
, 1);
122 PATH_MoveTo(dc
, pPath
);
123 for (i
= 1; i
< Count
; ++i
)
125 PATH_LineTo(dc
, Points
[i
].x
, Points
[i
].y
);
127 PATH_LineTo(dc
, Points
[0].x
, Points
[0].y
);
130 pPath
->state
= PATH_Closed
;
131 dc
->dclevel
.flPath
&= ~DCPATH_ACTIVE
;
133 /* Actually stroke a path */
134 ret
= PATH_StrokePath(dc
, pPath
);
137 PATH_UnlockPath(pPath
);
138 PATH_Delete(dc
->dclevel
.hPath
);
139 dc
->dclevel
.hPath
= NULL
;
143 for (i
= 0; i
< Count
-1; i
++)
145 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
146 // Points[0].x, Points[0].y,
147 // Points[1].x, Points[1].y );
149 ret
= IntEngLineTo(&psurf
->SurfObj
,
151 &dc
->eboLine
.BrushObject
,
152 Points
[i
].x
, /* From */
154 Points
[i
+1].x
, /* To */
157 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
160 /* Close the polygon */
163 ret
= IntEngLineTo(&psurf
->SurfObj
,
165 &dc
->eboLine
.BrushObject
,
166 Points
[Count
-1].x
, /* From */
168 Points
[0].x
, /* To */
171 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
181 IntGdiPolyPolygon(DC
*dc
,
186 if (PATH_IsPathOpen(dc
->dclevel
))
187 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
191 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
193 Points
+=*PolyCounts
++;
199 IntPolygon(HDC hdc
, POINT
*Point
, int Count
)
204 pdc
= DC_LockDc(hdc
);
207 EngSetLastError(ERROR_INVALID_HANDLE
);
211 bResult
= IntGdiPolygon(pdc
, Point
, Count
);
218 /******************************************************************************/
227 * This function uses optimized Bresenham's ellipse algorithm. It draws
228 * four lines of the ellipse in one pass.
245 LONG PenWidth
, PenOrigWidth
;
246 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
247 PBRUSH pFillBrushObj
;
248 BRUSH tmpFillBrushObj
;
253 EngSetLastError(ERROR_INVALID_HANDLE
);
257 if (PATH_IsPathOpen(dc
->dclevel
))
259 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
265 //// Could this use PATH_CheckCorners ?
267 if ((Left
== Right
) || (Top
== Bottom
))
275 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
279 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
283 pdcattr
= dc
->pdcattr
;
285 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
286 DC_vUpdateFillBrush(dc
);
288 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
289 DC_vUpdateLineBrush(dc
);
291 pbrush
= PEN_ShareLockPen(pdcattr
->hpen
);
294 DPRINT1("Ellipse Fail 1\n");
296 EngSetLastError(ERROR_INTERNAL_ERROR
);
300 PenOrigWidth
= PenWidth
= pbrush
->lWidth
;
301 if (pbrush
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
303 if (pbrush
->ulPenStyle
== PS_INSIDEFRAME
)
305 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
306 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
307 Left
+= PenWidth
/ 2;
308 Right
-= (PenWidth
- 1) / 2;
310 Bottom
-= (PenWidth
- 1) / 2;
313 if (!PenWidth
) PenWidth
= 1;
314 pbrush
->lWidth
= PenWidth
;
316 RectBounds
.left
= Left
;
317 RectBounds
.right
= Right
;
318 RectBounds
.top
= Top
;
319 RectBounds
.bottom
= Bottom
;
321 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
323 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
324 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
325 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
326 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
328 // Setup for dynamic width and height.
329 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
330 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
331 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
332 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
334 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
335 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
337 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
338 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
340 pFillBrushObj
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
341 if (NULL
== pFillBrushObj
)
343 DPRINT1("FillEllipse Fail\n");
344 EngSetLastError(ERROR_INTERNAL_ERROR
);
349 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
350 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
351 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
352 tmpFillBrushObj
.ptOrigin
.x
+= dc
->ptlDCOrig
.x
;
353 tmpFillBrushObj
.ptOrigin
.y
+= dc
->ptlDCOrig
.y
;
355 DC_vPrepareDCsForBlit(dc
, &RectBounds
, NULL
, NULL
);
357 ret
= IntFillEllipse( dc
,
363 BRUSH_ShareUnlockBrush(pFillBrushObj
);
367 ret
= IntDrawEllipse( dc
,
375 DC_vFinishBlit(dc
, NULL
);
378 pbrush
->lWidth
= PenOrigWidth
;
379 PEN_ShareUnlockPen(pbrush
);
381 DPRINT("Ellipse Exit.\n");
387 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
388 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
389 // first and second side, between the third and fourth side, and so on.
391 // WINDING Selects winding mode (fills any region with a nonzero winding value).
392 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
393 // This value is defined as the number of times a pen used to draw the polygon would go around the region.
394 // The direction of each edge of the polygon is important.
396 extern BOOL
FillPolygon(PDC dc
,
409 NtGdiPolyPolyDraw( IN HDC hDC
,
410 IN PPOINT UnsafePoints
,
411 IN PULONG UnsafeCounts
,
419 NTSTATUS Status
= STATUS_SUCCESS
;
421 ULONG nPoints
= 0, nMaxPoints
= 0, nInvalid
= 0, i
;
423 if (!UnsafePoints
|| !UnsafeCounts
||
424 Count
== 0 || iFunc
== 0 || iFunc
> GdiPolyPolyRgn
)
426 /* Windows doesn't set last error */
432 ProbeForRead(UnsafePoints
, Count
* sizeof(POINT
), 1);
433 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
435 /* Count points and validate poligons */
436 for (i
= 0; i
< Count
; i
++)
438 if (UnsafeCounts
[i
] < 2)
442 nPoints
+= UnsafeCounts
[i
];
443 nMaxPoints
= max(nMaxPoints
, UnsafeCounts
[i
]);
446 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
448 Status
= _SEH2_GetExceptionCode();
452 if (!NT_SUCCESS(Status
))
454 /* Windows doesn't set last error */
458 if (nPoints
== 0 || nPoints
< nMaxPoints
)
460 /* If all polygon counts are zero, or we have overflow,
461 return without setting a last error code. */
467 /* If at least one poly count is 0 or 1, fail */
468 EngSetLastError(ERROR_INVALID_PARAMETER
);
472 /* Allocate one buffer for both counts and points */
473 pTemp
= ExAllocatePoolWithTag(PagedPool
,
474 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
478 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
483 SafePoints
= (PVOID
)(SafeCounts
+ Count
);
487 /* Pointers already probed! */
488 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
489 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
491 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
493 Status
= _SEH2_GetExceptionCode();
497 if (!NT_SUCCESS(Status
))
499 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
503 /* Special handling for GdiPolyPolyRgn */
504 if (iFunc
== GdiPolyPolyRgn
)
506 INT iMode
= (INT
)(UINT_PTR
)hDC
;
509 hrgn
= GreCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, iMode
);
511 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
512 return (ULONG_PTR
)hrgn
;
518 EngSetLastError(ERROR_INVALID_HANDLE
);
519 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
523 DC_vPrepareDCsForBlit(dc
, NULL
, NULL
, NULL
);
525 if (dc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
526 DC_vUpdateFillBrush(dc
);
528 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
529 DC_vUpdateLineBrush(dc
);
531 /* Perform the actual work */
535 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
537 case GdiPolyPolyLine
:
538 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
541 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
544 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
546 case GdiPolyBezierTo
:
547 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
550 EngSetLastError(ERROR_INVALID_PARAMETER
);
554 /* Cleanup and return */
555 DC_vFinishBlit(dc
, NULL
);
557 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
559 return (ULONG_PTR
)Ret
;
571 SURFACE
*psurf
= NULL
;
572 PBRUSH pbrLine
, pbrFill
;
573 BOOL ret
= FALSE
; // Default to failure
580 ASSERT ( dc
); // Caller's responsibility to set this up
582 pdcattr
= dc
->pdcattr
;
584 // Rectangle Path only.
585 if ( PATH_IsPathOpen(dc
->dclevel
) )
587 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
590 /* Make sure rectangle is not inverted */
591 DestRect
.left
= min(LeftRect
, RightRect
);
592 DestRect
.right
= max(LeftRect
, RightRect
);
593 DestRect
.top
= min(TopRect
, BottomRect
);
594 DestRect
.bottom
= max(TopRect
, BottomRect
);
596 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
598 DestRect
.left
+= dc
->ptlDCOrig
.x
;
599 DestRect
.right
+= dc
->ptlDCOrig
.x
;
600 DestRect
.top
+= dc
->ptlDCOrig
.y
;
601 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
603 if (dc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
605 IntUpdateBoundsRect(dc
, &DestRect
);
608 /* In GM_COMPATIBLE, don't include bottom and right edges */
609 if (pdcattr
->iGraphicsMode
== GM_COMPATIBLE
)
615 DC_vPrepareDCsForBlit(dc
, &DestRect
, NULL
, NULL
);
617 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
618 DC_vUpdateFillBrush(dc
);
620 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
621 DC_vUpdateLineBrush(dc
);
623 pbrFill
= dc
->dclevel
.pbrFill
;
624 pbrLine
= dc
->dclevel
.pbrLine
;
631 psurf
= dc
->dclevel
.pSurface
;
640 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
642 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
643 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
644 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
645 ret
= IntEngBitBlt(&psurf
->SurfObj
,
653 &dc
->eboFill
.BrushObject
,
655 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY
));
659 // Draw the rectangle with the current pen
661 ret
= TRUE
; // Change default to success
663 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
665 if (IntIsEffectiveWidePen(pbrLine
))
668 PATH_Delete(dc
->dclevel
.hPath
);
669 dc
->dclevel
.hPath
= NULL
;
672 pPath
= PATH_CreatePath(5);
673 dc
->dclevel
.flPath
|= DCPATH_ACTIVE
;
674 dc
->dclevel
.hPath
= pPath
->BaseObject
.hHmgr
;
675 pPath
->pos
.x
= LeftRect
;
676 pPath
->pos
.y
= TopRect
;
677 IntLPtoDP(dc
, &pPath
->pos
, 1);
679 PATH_MoveTo(dc
, pPath
);
680 PATH_LineTo(dc
, RightRect
, TopRect
);
681 PATH_LineTo(dc
, RightRect
, BottomRect
);
682 PATH_LineTo(dc
, LeftRect
, BottomRect
);
683 PATH_LineTo(dc
, LeftRect
, TopRect
);
686 pPath
->state
= PATH_Closed
;
687 dc
->dclevel
.flPath
&= ~DCPATH_ACTIVE
;
689 /* Actually stroke a path */
690 ret
= PATH_StrokePath(dc
, pPath
);
693 PATH_UnlockPath(pPath
);
694 PATH_Delete(dc
->dclevel
.hPath
);
695 dc
->dclevel
.hPath
= NULL
;
699 Mix
= ROP2_TO_MIX(pdcattr
->jROP2
);
700 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
702 &dc
->eboLine
.BrushObject
,
703 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
704 &DestRect
, // Bounding rectangle
707 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
709 &dc
->eboLine
.BrushObject
,
710 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
711 &DestRect
, // Bounding rectangle
714 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
716 &dc
->eboLine
.BrushObject
,
717 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
718 &DestRect
, // Bounding rectangle
721 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
723 &dc
->eboLine
.BrushObject
,
724 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
725 &DestRect
, // Bounding rectangle
731 DC_vFinishBlit(dc
, NULL
);
733 /* Move current position in DC?
734 MSDN: The current position is neither used nor updated by Rectangle. */
741 NtGdiRectangle(HDC hDC
,
748 BOOL ret
; // Default to failure
753 EngSetLastError(ERROR_INVALID_HANDLE
);
757 /* Do we rotate or shear? */
758 if (!(dc
->pdcattr
->mxWorldToDevice
.flAccel
& XFORM_SCALE
))
760 POINTL DestCoords
[4];
761 ULONG PolyCounts
= 4;
763 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
764 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
765 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
766 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
767 // Use IntGdiPolyPolygon so to support PATH.
768 ret
= IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
772 ret
= IntRectangle(dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
793 PBRUSH pbrLine
, pbrFill
;
795 LONG PenWidth
, PenOrigWidth
;
796 BOOL ret
= TRUE
; // Default to success
799 ASSERT ( dc
); // Caller's responsibility to set this up
801 if ( PATH_IsPathOpen(dc
->dclevel
) )
802 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
803 xCurveDiameter
, yCurveDiameter
);
805 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
807 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
808 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
812 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
816 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
819 pdcattr
= dc
->pdcattr
;
821 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
822 DC_vUpdateFillBrush(dc
);
824 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
825 DC_vUpdateLineBrush(dc
);
827 pbrLine
= PEN_ShareLockPen(pdcattr
->hpen
);
830 /* Nothing to do, as we don't have a bitmap */
831 EngSetLastError(ERROR_INTERNAL_ERROR
);
835 PenOrigWidth
= PenWidth
= pbrLine
->lWidth
;
836 if (pbrLine
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
838 if (pbrLine
->ulPenStyle
== PS_INSIDEFRAME
)
840 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
841 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
842 Left
+= PenWidth
/ 2;
843 Right
-= (PenWidth
- 1) / 2;
845 Bottom
-= (PenWidth
- 1) / 2;
848 if (!PenWidth
) PenWidth
= 1;
849 pbrLine
->lWidth
= PenWidth
;
851 RectBounds
.left
= Left
;
852 RectBounds
.top
= Top
;
853 RectBounds
.right
= Right
;
854 RectBounds
.bottom
= Bottom
;
856 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
858 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
859 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
860 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
861 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
863 pbrFill
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
866 DPRINT1("FillRound Fail\n");
867 EngSetLastError(ERROR_INTERNAL_ERROR
);
873 DC_vPrepareDCsForBlit(dc
, &RectBounds
, NULL
, NULL
);
875 RtlCopyMemory(&brushTemp
, pbrFill
, sizeof(brushTemp
));
876 brushTemp
.ptOrigin
.x
+= RectBounds
.left
- Left
;
877 brushTemp
.ptOrigin
.y
+= RectBounds
.top
- Top
;
878 ret
= IntFillRoundRect( dc
,
886 BRUSH_ShareUnlockBrush(pbrFill
);
890 ret
= IntDrawRoundRect( dc
,
900 DC_vFinishBlit(dc
, NULL
);
904 pbrLine
->lWidth
= PenOrigWidth
;
905 PEN_ShareUnlockPen(pbrLine
);
920 DC
*dc
= DC_LockDc(hDC
);
921 BOOL ret
= FALSE
; /* Default to failure */
923 DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
926 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
927 EngSetLastError(ERROR_INVALID_HANDLE
);
931 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
956 /* Check parameters */
957 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
959 PGRADIENT_TRIANGLE pTriangle
= (PGRADIENT_TRIANGLE
)pMesh
;
961 for (i
= 0; i
< nMesh
; i
++, pTriangle
++)
963 if (pTriangle
->Vertex1
>= nVertex
||
964 pTriangle
->Vertex2
>= nVertex
||
965 pTriangle
->Vertex3
>= nVertex
)
967 EngSetLastError(ERROR_INVALID_PARAMETER
);
974 PGRADIENT_RECT pRect
= (PGRADIENT_RECT
)pMesh
;
975 for (i
= 0; i
< nMesh
; i
++, pRect
++)
977 if (pRect
->UpperLeft
>= nVertex
|| pRect
->LowerRight
>= nVertex
)
979 EngSetLastError(ERROR_INVALID_PARAMETER
);
985 /* Lock the output DC */
986 pdc
= DC_LockDc(hdc
);
989 EngSetLastError(ERROR_INVALID_HANDLE
);
993 if (!pdc
->dclevel
.pSurface
)
995 /* Memory DC with no surface selected */
997 return TRUE
; // CHECKME
1000 /* Calculate extent */
1001 rclExtent
.left
= rclExtent
.right
= pVertex
->x
;
1002 rclExtent
.top
= rclExtent
.bottom
= pVertex
->y
;
1003 for (i
= 0; i
< nVertex
; i
++)
1005 rclExtent
.left
= min(rclExtent
.left
, (pVertex
+ i
)->x
);
1006 rclExtent
.right
= max(rclExtent
.right
, (pVertex
+ i
)->x
);
1007 rclExtent
.top
= min(rclExtent
.top
, (pVertex
+ i
)->y
);
1008 rclExtent
.bottom
= max(rclExtent
.bottom
, (pVertex
+ i
)->y
);
1010 IntLPtoDP(pdc
, (LPPOINT
)&rclExtent
, 2);
1012 rclExtent
.left
+= pdc
->ptlDCOrig
.x
;
1013 rclExtent
.right
+= pdc
->ptlDCOrig
.x
;
1014 rclExtent
.top
+= pdc
->ptlDCOrig
.y
;
1015 rclExtent
.bottom
+= pdc
->ptlDCOrig
.y
;
1017 if (RECTL_bIsEmptyRect(&rclExtent
))
1023 ptlDitherOrg
.x
= ptlDitherOrg
.y
= 0;
1024 IntLPtoDP(pdc
, (LPPOINT
)&ptlDitherOrg
, 1);
1026 ptlDitherOrg
.x
+= pdc
->ptlDCOrig
.x
;
1027 ptlDitherOrg
.y
+= pdc
->ptlDCOrig
.y
;
1029 if (pdc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
1031 IntUpdateBoundsRect(pdc
, &rclExtent
);
1034 DC_vPrepareDCsForBlit(pdc
, &rclExtent
, NULL
, NULL
);
1036 psurf
= pdc
->dclevel
.pSurface
;
1038 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0, 0);
1040 bRet
= IntEngGradientFill(&psurf
->SurfObj
,
1041 (CLIPOBJ
*)&pdc
->co
,
1051 EXLATEOBJ_vCleanup(&exlo
);
1052 DC_vFinishBlit(pdc
, NULL
);
1069 PTRIVERTEX SafeVertex
;
1071 ULONG cbVertex
, cbMesh
;
1073 /* Validate parameters */
1074 if (!pVertex
|| !nVertex
|| !pMesh
|| !nMesh
)
1076 EngSetLastError(ERROR_INVALID_PARAMETER
);
1082 case GRADIENT_FILL_RECT_H
:
1083 case GRADIENT_FILL_RECT_V
:
1084 cbMesh
= nMesh
* sizeof(GRADIENT_RECT
);
1086 case GRADIENT_FILL_TRIANGLE
:
1087 cbMesh
= nMesh
* sizeof(GRADIENT_TRIANGLE
);
1090 EngSetLastError(ERROR_INVALID_PARAMETER
);
1094 cbVertex
= nVertex
* sizeof(TRIVERTEX
) ;
1095 if(cbVertex
+ cbMesh
<= cbVertex
)
1101 /* Allocate a kernel mode buffer */
1102 SafeVertex
= ExAllocatePoolWithTag(PagedPool
, cbVertex
+ cbMesh
, TAG_SHAPE
);
1105 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1109 SafeMesh
= (PVOID
)((ULONG_PTR
)SafeVertex
+ cbVertex
);
1111 /* Copy the parameters to kernel mode */
1114 ProbeForRead(pVertex
, cbVertex
, 1);
1115 ProbeForRead(pMesh
, cbMesh
, 1);
1116 RtlCopyMemory(SafeVertex
, pVertex
, cbVertex
);
1117 RtlCopyMemory(SafeMesh
, pMesh
, cbMesh
);
1119 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1121 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1122 SetLastNtError(_SEH2_GetExceptionCode());
1123 _SEH2_YIELD(return FALSE
;)
1127 /* Call the internal function */
1128 bRet
= GreGradientFill(hdc
, SafeVertex
, nVertex
, SafeMesh
, nMesh
, ulMode
);
1130 /* Cleanup and return result */
1131 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1155 dc
= DC_LockDc(hDC
);
1158 EngSetLastError(ERROR_INVALID_HANDLE
);
1162 if (!dc
->dclevel
.pSurface
)
1169 pdcattr
= dc
->pdcattr
;
1174 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1176 DC_vPrepareDCsForBlit(dc
, &DestRect
, NULL
, NULL
);
1178 psurf
= dc
->dclevel
.pSurface
;
1180 prgn
= dc
->prgnRao
? dc
->prgnRao
: dc
->prgnVis
;
1183 Ret
= REGION_PtInRegion(prgn
, Pt
.x
, Pt
.y
);
1185 REGION_GetRgnBox(prgn
, (LPRECT
)&DestRect
);
1188 DC_vFinishBlit(dc
, NULL
);
1194 RECTL_vSetRect(&DestRect
, 0, 0, psurf
->SurfObj
.sizlBitmap
.cx
, psurf
->SurfObj
.sizlBitmap
.cy
);
1197 if (dc
->fs
& (DC_ACCUM_APP
|DC_ACCUM_WMGR
))
1199 IntUpdateBoundsRect(dc
, &DestRect
);
1202 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0xffffff, 0);
1204 /* Only solid fills supported for now
1205 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1206 * Version a (most likely slow): call DrvPatBlt for every pixel
1207 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1208 ConvColor
= XLATEOBJ_iXlate(&exlo
.xlo
, Color
);
1209 Ret
= DIB_XXBPP_FloodFillSolid(&psurf
->SurfObj
, &dc
->eboFill
.BrushObject
, &DestRect
, &Pt
, ConvColor
, FillType
);
1211 DC_vFinishBlit(dc
, NULL
);
1213 EXLATEOBJ_vCleanup(&exlo
);