2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: subsystems/win32/win32k/objects/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
;
84 /* FIXME: psurf can be NULL!!!! don't assert but handle this case gracefully! */
87 /* Now fill the polygon with the current fill brush. */
88 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
90 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
91 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
92 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
93 ret
= IntFillPolygon (dc
,
95 &dc
->eboFill
.BrushObject
,
102 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
103 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
107 for (i
= 0; i
< Count
-1; i
++)
110 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
111 // Points[0].x, Points[0].y,
112 // Points[1].x, Points[1].y );
114 ret
= IntEngLineTo(&psurf
->SurfObj
,
115 dc
->rosdc
.CombinedClip
,
116 &dc
->eboLine
.BrushObject
,
117 Points
[i
].x
, /* From */
119 Points
[i
+1].x
, /* To */
122 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
125 /* Close the polygon */
128 ret
= IntEngLineTo(&psurf
->SurfObj
,
129 dc
->rosdc
.CombinedClip
,
130 &dc
->eboLine
.BrushObject
,
131 Points
[Count
-1].x
, /* From */
133 Points
[0].x
, /* To */
136 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
145 IntGdiPolyPolygon(DC
*dc
,
150 if (PATH_IsPathOpen(dc
->dclevel
))
151 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
155 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
157 Points
+=*PolyCounts
++;
164 /******************************************************************************/
173 * This function uses optimized Bresenham's ellipse algorithm. It draws
174 * four lines of the ellipse in one pass.
191 LONG PenWidth
, PenOrigWidth
;
192 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
193 PBRUSH pFillBrushObj
;
194 BRUSH tmpFillBrushObj
;
196 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
201 EngSetLastError(ERROR_INVALID_HANDLE
);
204 if (dc
->dctype
== DC_TYPE_INFO
)
207 /* Yes, Windows really returns TRUE in this case */
211 if (PATH_IsPathOpen(dc
->dclevel
))
213 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
220 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
224 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
227 pdcattr
= dc
->pdcattr
;
229 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
230 DC_vUpdateFillBrush(dc
);
232 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
233 DC_vUpdateLineBrush(dc
);
235 pbrush
= PEN_ShareLockPen(pdcattr
->hpen
);
238 DPRINT1("Ellipse Fail 1\n");
240 EngSetLastError(ERROR_INTERNAL_ERROR
);
244 PenOrigWidth
= PenWidth
= pbrush
->ptPenWidth
.x
;
245 if (pbrush
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
247 if (pbrush
->ulPenStyle
== PS_INSIDEFRAME
)
249 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
250 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
251 Left
+= PenWidth
/ 2;
252 Right
-= (PenWidth
- 1) / 2;
254 Bottom
-= (PenWidth
- 1) / 2;
257 if (!PenWidth
) PenWidth
= 1;
258 pbrush
->ptPenWidth
.x
= PenWidth
;
260 RectBounds
.left
= Left
;
261 RectBounds
.right
= Right
;
262 RectBounds
.top
= Top
;
263 RectBounds
.bottom
= Bottom
;
265 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
267 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
268 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
269 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
270 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
272 // Setup for dynamic width and height.
273 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
274 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
275 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
276 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
278 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
279 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
281 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
282 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
284 pFillBrushObj
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
285 if (NULL
== pFillBrushObj
)
287 DPRINT1("FillEllipse Fail\n");
288 EngSetLastError(ERROR_INTERNAL_ERROR
);
293 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
294 //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
295 //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
296 tmpFillBrushObj
.ptOrigin
.x
+= dc
->ptlDCOrig
.x
;
297 tmpFillBrushObj
.ptOrigin
.y
+= dc
->ptlDCOrig
.y
;
298 ret
= IntFillEllipse( dc
,
304 BRUSH_ShareUnlockBrush(pFillBrushObj
);
308 ret
= IntDrawEllipse( dc
,
315 pbrush
->ptPenWidth
.x
= PenOrigWidth
;
316 PEN_ShareUnlockPen(pbrush
);
318 DPRINT("Ellipse Exit.\n");
324 // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
325 // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
326 // first and second side, between the third and fourth side, and so on.
328 // WINDING Selects winding mode (fills any region with a nonzero winding value).
329 // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
330 // This value is defined as the number of times a pen used to draw the polygon would go around the region.
331 // The direction of each edge of the polygon is important.
333 extern BOOL
FillPolygon(PDC dc
,
346 NtGdiPolyPolyDraw( IN HDC hDC
,
347 IN PPOINT UnsafePoints
,
348 IN PULONG UnsafeCounts
,
356 NTSTATUS Status
= STATUS_SUCCESS
;
358 ULONG nPoints
= 0, nMaxPoints
= 0, nInvalid
= 0, i
;
360 if (!UnsafePoints
|| !UnsafeCounts
||
361 Count
== 0 || iFunc
== 0 || iFunc
> GdiPolyPolyRgn
)
363 /* Windows doesn't set last error */
369 ProbeForRead(UnsafePoints
, Count
* sizeof(POINT
), 1);
370 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
372 /* Count points and validate poligons */
373 for (i
= 0; i
< Count
; i
++)
375 if (UnsafeCounts
[i
] < 2)
379 nPoints
+= UnsafeCounts
[i
];
380 nMaxPoints
= max(nMaxPoints
, UnsafeCounts
[i
]);
383 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
385 Status
= _SEH2_GetExceptionCode();
389 if (!NT_SUCCESS(Status
))
391 /* Windows doesn't set last error */
395 if (nPoints
== 0 || nPoints
< nMaxPoints
)
397 /* If all polygon counts are zero, or we have overflow,
398 return without setting a last error code. */
404 /* If at least one poly count is 0 or 1, fail */
405 EngSetLastError(ERROR_INVALID_PARAMETER
);
409 /* Allocate one buffer for both counts and points */
410 pTemp
= ExAllocatePoolWithTag(PagedPool
,
411 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
415 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
420 SafePoints
= (PVOID
)(SafeCounts
+ Count
);
424 /* Pointers already probed! */
425 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
426 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
428 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
430 Status
= _SEH2_GetExceptionCode();
434 if (!NT_SUCCESS(Status
))
436 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
440 /* Special handling for GdiPolyPolyRgn */
441 if (iFunc
== GdiPolyPolyRgn
)
444 hRgn
= IntCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, (INT_PTR
)hDC
);
445 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
446 return (ULONG_PTR
)hRgn
;
452 EngSetLastError(ERROR_INVALID_HANDLE
);
453 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
457 if (dc
->dctype
== DC_TYPE_INFO
)
460 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
461 /* Yes, Windows really returns TRUE in this case */
465 DC_vPrepareDCsForBlit(dc
, dc
->rosdc
.CombinedClip
->rclBounds
,
466 NULL
, dc
->rosdc
.CombinedClip
->rclBounds
);
468 if (dc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
469 DC_vUpdateFillBrush(dc
);
471 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
472 DC_vUpdateLineBrush(dc
);
474 /* Perform the actual work */
478 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
480 case GdiPolyPolyLine
:
481 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
484 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
487 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
489 case GdiPolyBezierTo
:
490 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
493 EngSetLastError(ERROR_INVALID_PARAMETER
);
497 /* Cleanup and return */
498 DC_vFinishBlit(dc
, NULL
);
500 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
502 return (ULONG_PTR
)Ret
;
514 SURFACE
*psurf
= NULL
;
515 PBRUSH pbrLine
, pbrFill
;
516 BOOL ret
= FALSE
; // Default to failure
522 ASSERT ( dc
); // Caller's responsibility to set this up
524 pdcattr
= dc
->pdcattr
;
526 // Rectangle Path only.
527 if ( PATH_IsPathOpen(dc
->dclevel
) )
529 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
532 /* Make sure rectangle is not inverted */
533 DestRect
.left
= min(LeftRect
, RightRect
);
534 DestRect
.right
= max(LeftRect
, RightRect
);
535 DestRect
.top
= min(TopRect
, BottomRect
);
536 DestRect
.bottom
= max(TopRect
, BottomRect
);
538 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
540 DestRect
.left
+= dc
->ptlDCOrig
.x
;
541 DestRect
.right
+= dc
->ptlDCOrig
.x
;
542 DestRect
.top
+= dc
->ptlDCOrig
.y
;
543 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
545 /* In GM_COMPATIBLE, don't include bottom and right edges */
546 if (pdcattr
->iGraphicsMode
== GM_COMPATIBLE
)
552 DC_vPrepareDCsForBlit(dc
, DestRect
, NULL
, DestRect
);
554 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
555 DC_vUpdateFillBrush(dc
);
557 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
558 DC_vUpdateLineBrush(dc
);
560 pbrFill
= dc
->dclevel
.pbrFill
;
561 pbrLine
= dc
->dclevel
.pbrLine
;
568 psurf
= dc
->dclevel
.pSurface
;
577 if (!(pbrFill
->flAttrs
& BR_IS_NULL
))
579 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
580 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
581 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
582 ret
= IntEngBitBlt(&psurf
->SurfObj
,
585 dc
->rosdc
.CombinedClip
,
590 &dc
->eboFill
.BrushObject
,
592 ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY
));
596 // Draw the rectangle with the current pen
598 ret
= TRUE
; // Change default to success
600 if (!(pbrLine
->flAttrs
& BR_IS_NULL
))
602 Mix
= ROP2_TO_MIX(pdcattr
->jROP2
);
603 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
604 dc
->rosdc
.CombinedClip
,
605 &dc
->eboLine
.BrushObject
,
606 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
607 &DestRect
, // Bounding rectangle
610 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
611 dc
->rosdc
.CombinedClip
,
612 &dc
->eboLine
.BrushObject
,
613 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
614 &DestRect
, // Bounding rectangle
617 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
618 dc
->rosdc
.CombinedClip
,
619 &dc
->eboLine
.BrushObject
,
620 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
621 &DestRect
, // Bounding rectangle
624 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
625 dc
->rosdc
.CombinedClip
,
626 &dc
->eboLine
.BrushObject
,
627 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
628 &DestRect
, // Bounding rectangle
633 DC_vFinishBlit(dc
, NULL
);
635 /* Move current position in DC?
636 MSDN: The current position is neither used nor updated by Rectangle. */
643 NtGdiRectangle(HDC hDC
,
650 BOOL ret
; // Default to failure
655 EngSetLastError(ERROR_INVALID_HANDLE
);
658 if (dc
->dctype
== DC_TYPE_INFO
)
661 /* Yes, Windows really returns TRUE in this case */
665 /* Do we rotate or shear? */
666 if (!(dc
->pdcattr
->mxWorldToDevice
.flAccel
& XFORM_SCALE
))
668 POINTL DestCoords
[4];
669 ULONG PolyCounts
= 4;
671 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
672 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
673 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
674 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
675 // Use IntGdiPolyPolygon so to support PATH.
676 ret
= IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
680 ret
= IntRectangle(dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
701 PBRUSH pbrLine
, pbrFill
;
703 LONG PenWidth
, PenOrigWidth
;
704 BOOL ret
= TRUE
; // Default to success
707 ASSERT ( dc
); // Caller's responsibility to set this up
709 if ( PATH_IsPathOpen(dc
->dclevel
) )
710 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
711 xCurveDiameter
, yCurveDiameter
);
713 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
715 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
716 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
720 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
724 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
727 pdcattr
= dc
->pdcattr
;
729 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
730 DC_vUpdateFillBrush(dc
);
732 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
733 DC_vUpdateLineBrush(dc
);
735 pbrLine
= PEN_ShareLockPen(pdcattr
->hpen
);
738 /* Nothing to do, as we don't have a bitmap */
739 EngSetLastError(ERROR_INTERNAL_ERROR
);
743 PenOrigWidth
= PenWidth
= pbrLine
->ptPenWidth
.x
;
744 if (pbrLine
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
746 if (pbrLine
->ulPenStyle
== PS_INSIDEFRAME
)
748 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
749 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
750 Left
+= PenWidth
/ 2;
751 Right
-= (PenWidth
- 1) / 2;
753 Bottom
-= (PenWidth
- 1) / 2;
756 if (!PenWidth
) PenWidth
= 1;
757 pbrLine
->ptPenWidth
.x
= PenWidth
;
759 RectBounds
.left
= Left
;
760 RectBounds
.top
= Top
;
761 RectBounds
.right
= Right
;
762 RectBounds
.bottom
= Bottom
;
764 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
766 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
767 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
768 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
769 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
771 pbrFill
= BRUSH_ShareLockBrush(pdcattr
->hbrush
);
774 DPRINT1("FillRound Fail\n");
775 EngSetLastError(ERROR_INTERNAL_ERROR
);
780 RtlCopyMemory(&brushTemp
, pbrFill
, sizeof(brushTemp
));
781 brushTemp
.ptOrigin
.x
+= RectBounds
.left
- Left
;
782 brushTemp
.ptOrigin
.y
+= RectBounds
.top
- Top
;
783 ret
= IntFillRoundRect( dc
,
791 BRUSH_ShareUnlockBrush(pbrFill
);
795 ret
= IntDrawRoundRect( dc
,
804 pbrLine
->ptPenWidth
.x
= PenOrigWidth
;
805 PEN_ShareUnlockPen(pbrLine
);
820 DC
*dc
= DC_LockDc(hDC
);
821 BOOL ret
= FALSE
; /* Default to failure */
823 DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
826 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
827 EngSetLastError(ERROR_INVALID_HANDLE
);
829 else if (dc
->dctype
== DC_TYPE_INFO
)
832 /* Yes, Windows really returns TRUE in this case */
837 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
862 /* Check parameters */
863 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
865 PGRADIENT_TRIANGLE pTriangle
= (PGRADIENT_TRIANGLE
)pMesh
;
867 for (i
= 0; i
< nMesh
; i
++, pTriangle
++)
869 if (pTriangle
->Vertex1
>= nVertex
||
870 pTriangle
->Vertex2
>= nVertex
||
871 pTriangle
->Vertex3
>= nVertex
)
873 EngSetLastError(ERROR_INVALID_PARAMETER
);
880 PGRADIENT_RECT pRect
= (PGRADIENT_RECT
)pMesh
;
881 for (i
= 0; i
< nMesh
; i
++, pRect
++)
883 if (pRect
->UpperLeft
>= nVertex
|| pRect
->LowerRight
>= nVertex
)
885 EngSetLastError(ERROR_INVALID_PARAMETER
);
891 /* Lock the output DC */
892 pdc
= DC_LockDc(hdc
);
895 EngSetLastError(ERROR_INVALID_HANDLE
);
899 if(pdc
->dctype
== DC_TYPE_INFO
)
902 /* Yes, Windows really returns TRUE in this case */
906 psurf
= pdc
->dclevel
.pSurface
;
909 /* Memory DC with no surface selected */
911 return TRUE
; // CHECKME
914 /* Calculate extent */
915 rclExtent
.left
= rclExtent
.right
= pVertex
->x
;
916 rclExtent
.top
= rclExtent
.bottom
= pVertex
->y
;
917 for (i
= 0; i
< nVertex
; i
++)
919 rclExtent
.left
= min(rclExtent
.left
, (pVertex
+ i
)->x
);
920 rclExtent
.right
= max(rclExtent
.right
, (pVertex
+ i
)->x
);
921 rclExtent
.top
= min(rclExtent
.top
, (pVertex
+ i
)->y
);
922 rclExtent
.bottom
= max(rclExtent
.bottom
, (pVertex
+ i
)->y
);
924 IntLPtoDP(pdc
, (LPPOINT
)&rclExtent
, 2);
926 rclExtent
.left
+= pdc
->ptlDCOrig
.x
;
927 rclExtent
.right
+= pdc
->ptlDCOrig
.x
;
928 rclExtent
.top
+= pdc
->ptlDCOrig
.y
;
929 rclExtent
.bottom
+= pdc
->ptlDCOrig
.y
;
931 ptlDitherOrg
.x
= ptlDitherOrg
.y
= 0;
932 IntLPtoDP(pdc
, (LPPOINT
)&ptlDitherOrg
, 1);
934 ptlDitherOrg
.x
+= pdc
->ptlDCOrig
.x
;
935 ptlDitherOrg
.y
+= pdc
->ptlDCOrig
.y
;
937 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0, 0);
939 ASSERT(pdc
->rosdc
.CombinedClip
);
941 DC_vPrepareDCsForBlit(pdc
, rclExtent
, NULL
, rclExtent
);
943 bRet
= IntEngGradientFill(&psurf
->SurfObj
,
944 pdc
->rosdc
.CombinedClip
,
954 EXLATEOBJ_vCleanup(&exlo
);
955 DC_vFinishBlit(pdc
, NULL
);
972 PTRIVERTEX SafeVertex
;
974 ULONG cbVertex
, cbMesh
;
976 /* Validate parameters */
977 if (!pVertex
|| !nVertex
|| !pMesh
|| !nMesh
)
979 EngSetLastError(ERROR_INVALID_PARAMETER
);
985 case GRADIENT_FILL_RECT_H
:
986 case GRADIENT_FILL_RECT_V
:
987 cbMesh
= nMesh
* sizeof(GRADIENT_RECT
);
989 case GRADIENT_FILL_TRIANGLE
:
990 cbMesh
= nMesh
* sizeof(GRADIENT_TRIANGLE
);
993 EngSetLastError(ERROR_INVALID_PARAMETER
);
997 cbVertex
= nVertex
* sizeof(TRIVERTEX
) ;
998 if(cbVertex
+ cbMesh
<= cbVertex
)
1004 /* Allocate a kernel mode buffer */
1005 SafeVertex
= ExAllocatePoolWithTag(PagedPool
, cbVertex
+ cbMesh
, TAG_SHAPE
);
1008 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1012 SafeMesh
= (PVOID
)((ULONG_PTR
)SafeVertex
+ cbVertex
);
1014 /* Copy the parameters to kernel mode */
1017 ProbeForRead(pVertex
, cbVertex
, 1);
1018 ProbeForRead(pMesh
, cbMesh
, 1);
1019 RtlCopyMemory(SafeVertex
, pVertex
, cbVertex
);
1020 RtlCopyMemory(SafeMesh
, pMesh
, cbMesh
);
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1024 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1025 SetLastNtError(_SEH2_GetExceptionCode());
1026 _SEH2_YIELD(return FALSE
;)
1030 /* Call the internal function */
1031 bRet
= GreGradientFill(hdc
, SafeVertex
, nVertex
, SafeMesh
, nMesh
, ulMode
);
1033 /* Cleanup and return result */
1034 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1048 SURFACE
*psurf
= NULL
;
1055 dc
= DC_LockDc(hDC
);
1058 EngSetLastError(ERROR_INVALID_HANDLE
);
1061 if (dc
->dctype
== DC_TYPE_INFO
)
1064 /* Yes, Windows really returns TRUE in this case */
1068 pdcattr
= dc
->pdcattr
;
1070 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
1071 DC_vUpdateFillBrush(dc
);
1073 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
1074 DC_vUpdateLineBrush(dc
);
1078 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1080 Ret
= NtGdiPtInRegion(dc
->rosdc
.hGCClipRgn
, Pt
.x
, Pt
.y
);
1082 IntGdiGetRgnBox(dc
->rosdc
.hGCClipRgn
,(LPRECT
)&DestRect
);
1086 psurf
= dc
->dclevel
.pSurface
;
1093 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, psurf
->ppal
, 0, 0xffffff, 0);
1095 /* Only solid fills supported for now
1096 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1097 * Version a (most likely slow): call DrvPatBlt for every pixel
1098 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1099 ConvColor
= XLATEOBJ_iXlate(&exlo
.xlo
, Color
);
1100 Ret
= DIB_XXBPP_FloodFillSolid(&psurf
->SurfObj
, &dc
->eboFill
.BrushObject
, &DestRect
, &Pt
, ConvColor
, FillType
);
1102 EXLATEOBJ_vCleanup(&exlo
);