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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
26 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
28 BOOL FASTCALL
IntFillEllipse( PDC dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PBRUSH pbrush
);
29 BOOL FASTCALL
IntDrawEllipse( PDC dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PBRUSH pbrush
);
30 BOOL FASTCALL
IntFillRoundRect( PDC dc
, INT Left
, INT Top
, INT Right
, INT Bottom
, INT Wellipse
, INT Hellipse
, PBRUSH pbrush
);
31 BOOL FASTCALL
IntDrawRoundRect( PDC dc
, INT Left
, INT Top
, INT Right
, INT Bottom
, INT Wellipse
, INT Hellipse
, PBRUSH pbrush
);
39 PBRUSH pbrLine
, pbrFill
;
40 BOOL ret
= FALSE
; // default to failure
48 ASSERT(dc
); // caller's responsibility to pass a valid dc
50 if (!Points
|| Count
< 2 )
52 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
60 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
61 Left = min(Left, Points[CurrentPoint].x);
62 Top = min(Top, Points[CurrentPoint].y);
66 pdcattr
= dc
->pdcattr
;
68 /* Convert to screen coordinates */
69 IntLPtoDP(dc
, Points
, Count
);
70 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
72 Points
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
73 Points
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
75 // No need to have path here.
77 DestRect
.left
= Points
[0].x
;
78 DestRect
.right
= Points
[0].x
;
79 DestRect
.top
= Points
[0].y
;
80 DestRect
.bottom
= Points
[0].y
;
82 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
84 DestRect
.left
= min(DestRect
.left
, Points
[CurrentPoint
].x
);
85 DestRect
.right
= max(DestRect
.right
, Points
[CurrentPoint
].x
);
86 DestRect
.top
= min(DestRect
.top
, Points
[CurrentPoint
].y
);
87 DestRect
.bottom
= max(DestRect
.bottom
, Points
[CurrentPoint
].y
);
90 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
91 DC_vUpdateFillBrush(dc
);
93 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
94 DC_vUpdateLineBrush(dc
);
96 /* Special locking order to avoid lock-ups */
97 pbrFill
= dc
->dclevel
.pbrFill
;
98 pbrLine
= dc
->dclevel
.pbrLine
;
99 psurf
= dc
->dclevel
.pSurface
;
100 /* FIXME - psurf can be NULL!!!! don't assert but handle this case gracefully! */
103 /* Now fill the polygon with the current fill brush. */
104 if (!(pbrFill
->flAttrs
& GDIBRUSH_IS_NULL
))
106 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
107 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
108 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
109 ret
= IntFillPolygon (dc
,
111 &dc
->eboFill
.BrushObject
,
118 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
119 if (!(pbrLine
->flAttrs
& GDIBRUSH_IS_NULL
))
123 for (i
= 0; i
< Count
-1; i
++)
126 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
127 // Points[0].x, Points[0].y,
128 // Points[1].x, Points[1].y );
130 ret
= IntEngLineTo(&psurf
->SurfObj
,
131 dc
->rosdc
.CombinedClip
,
132 &dc
->eboLine
.BrushObject
,
133 Points
[i
].x
, /* From */
135 Points
[i
+1].x
, /* To */
138 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
141 /* Close the polygon */
144 ret
= IntEngLineTo(&psurf
->SurfObj
,
145 dc
->rosdc
.CombinedClip
,
146 &dc
->eboLine
.BrushObject
,
147 Points
[Count
-1].x
, /* From */
149 Points
[0].x
, /* To */
152 ROP2_TO_MIX(pdcattr
->jROP2
)); /* MIX */
161 IntGdiPolyPolygon(DC
*dc
,
166 if (PATH_IsPathOpen(dc
->dclevel
))
167 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
171 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
173 Points
+=*PolyCounts
++;
180 /******************************************************************************/
189 * This function uses optimized Bresenham's ellipse algorithm. It draws
190 * four lines of the ellipse in one pass.
207 LONG PenWidth
, PenOrigWidth
;
208 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
209 PBRUSH pFillBrushObj
;
210 BRUSH tmpFillBrushObj
;
212 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
217 SetLastWin32Error(ERROR_INVALID_HANDLE
);
220 if (dc
->dctype
== DC_TYPE_INFO
)
223 /* Yes, Windows really returns TRUE in this case */
227 if (PATH_IsPathOpen(dc
->dclevel
))
229 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
236 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
240 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
243 pdcattr
= dc
->pdcattr
;
245 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
246 DC_vUpdateFillBrush(dc
);
248 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
249 DC_vUpdateLineBrush(dc
);
251 pbrush
= PEN_LockPen(pdcattr
->hpen
);
254 DPRINT1("Ellipse Fail 1\n");
256 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
260 PenOrigWidth
= PenWidth
= pbrush
->ptPenWidth
.x
;
261 if (pbrush
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
263 if (pbrush
->ulPenStyle
== PS_INSIDEFRAME
)
265 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
266 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
267 Left
+= PenWidth
/ 2;
268 Right
-= (PenWidth
- 1) / 2;
270 Bottom
-= (PenWidth
- 1) / 2;
273 if (!PenWidth
) PenWidth
= 1;
274 pbrush
->ptPenWidth
.x
= PenWidth
;
276 RectBounds
.left
= Left
;
277 RectBounds
.right
= Right
;
278 RectBounds
.top
= Top
;
279 RectBounds
.bottom
= Bottom
;
281 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
283 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
284 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
285 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
286 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
288 // Setup for dynamic width and height.
289 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
290 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
291 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
292 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
294 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
295 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
297 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
298 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
300 pFillBrushObj
= BRUSH_LockBrush(pdcattr
->hbrush
);
301 if (NULL
== pFillBrushObj
)
303 DPRINT1("FillEllipse Fail\n");
304 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
309 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
310 // tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
311 // tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
312 tmpFillBrushObj
.ptOrigin
.x
+= dc
->ptlDCOrig
.x
;
313 tmpFillBrushObj
.ptOrigin
.y
+= dc
->ptlDCOrig
.y
;
314 ret
= IntFillEllipse( dc
,
320 BRUSH_UnlockBrush(pFillBrushObj
);
324 ret
= IntDrawEllipse( dc
,
331 pbrush
->ptPenWidth
.x
= PenOrigWidth
;
332 PEN_UnlockPen(pbrush
);
334 DPRINT("Ellipse Exit.\n");
340 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
341 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
342 //first and second side, between the third and fourth side, and so on.
344 //WINDING Selects winding mode (fills any region with a nonzero winding value).
345 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
346 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
347 //The direction of each edge of the polygon is important.
349 extern BOOL
FillPolygon(PDC dc
,
362 NtGdiPolyPolyDraw( IN HDC hDC
,
363 IN PPOINT UnsafePoints
,
364 IN PULONG UnsafeCounts
,
372 NTSTATUS Status
= STATUS_SUCCESS
;
374 INT nPoints
= 0, nMaxPoints
= 0, nInvalid
= 0, i
;
376 if (!UnsafePoints
|| !UnsafeCounts
||
377 Count
== 0 || iFunc
== 0 || iFunc
> GdiPolyPolyRgn
)
379 /* Windows doesn't set last error */
385 ProbeForRead(UnsafePoints
, Count
* sizeof(POINT
), 1);
386 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
388 /* Count points and validate poligons */
389 for (i
= 0; i
< Count
; i
++)
391 if (UnsafeCounts
[i
] < 2)
395 nPoints
+= UnsafeCounts
[i
];
396 nMaxPoints
= max(nMaxPoints
, UnsafeCounts
[i
]);
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
401 Status
= _SEH2_GetExceptionCode();
405 if (!NT_SUCCESS(Status
))
407 /* Windows doesn't set last error */
411 if (nPoints
== 0 || nPoints
< nMaxPoints
)
413 /* If all polygon counts are zero, or we have overflow,
414 return without setting a last error code. */
420 /* If at least one poly count is 0 or 1, fail */
421 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
425 /* Allocate one buffer for both counts and points */
426 pTemp
= ExAllocatePoolWithTag(PagedPool
,
427 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
431 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
436 SafePoints
= (PVOID
)(SafeCounts
+ Count
);
440 /* Pointers already probed! */
441 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
442 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
444 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
446 Status
= _SEH2_GetExceptionCode();
450 if (!NT_SUCCESS(Status
))
452 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
456 /* Special handling for GdiPolyPolyRgn */
457 if (iFunc
== GdiPolyPolyRgn
)
460 hRgn
= IntCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, (INT_PTR
)hDC
);
461 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
462 return (ULONG_PTR
)hRgn
;
468 SetLastWin32Error(ERROR_INVALID_HANDLE
);
473 if (dc
->dctype
== DC_TYPE_INFO
)
477 /* Yes, Windows really returns TRUE in this case */
481 DC_vPrepareDCsForBlit(dc
, dc
->rosdc
.CombinedClip
->rclBounds
,
482 NULL
, dc
->rosdc
.CombinedClip
->rclBounds
);
484 if (dc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
485 DC_vUpdateFillBrush(dc
);
487 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
488 DC_vUpdateLineBrush(dc
);
490 /* Perform the actual work */
494 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
496 case GdiPolyPolyLine
:
497 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
500 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
503 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
505 case GdiPolyBezierTo
:
506 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
509 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
513 /* Cleanup and return */
514 DC_vFinishBlit(dc
, NULL
);
518 return (ULONG_PTR
)Ret
;
530 SURFACE
*psurf
= NULL
;
531 PBRUSH pbrLine
, pbrFill
;
532 BOOL ret
= FALSE
; // default to failure
538 ASSERT ( dc
); // caller's responsibility to set this up
540 pdcattr
= dc
->pdcattr
;
542 /* Do we rotate or shear? */
543 if (!(dc
->dclevel
.mxWorldToDevice
.flAccel
& MX_SCALE
))
546 POINTL DestCoords
[4];
547 ULONG PolyCounts
= 4;
548 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
549 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
550 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
551 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
552 // Use IntGdiPolyPolygon so to support PATH.
553 return IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
555 // Rectangle Path only.
556 if ( PATH_IsPathOpen(dc
->dclevel
) )
558 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
561 DestRect
.left
= LeftRect
;
562 DestRect
.right
= RightRect
;
563 DestRect
.top
= TopRect
;
564 DestRect
.bottom
= BottomRect
;
566 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
568 DestRect
.left
+= dc
->ptlDCOrig
.x
;
569 DestRect
.right
+= dc
->ptlDCOrig
.x
;
570 DestRect
.top
+= dc
->ptlDCOrig
.y
;
571 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
573 /* In GM_COMPATIBLE, don't include bottom and right edges */
574 if (pdcattr
->iGraphicsMode
== GM_COMPATIBLE
)
580 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
581 DC_vUpdateFillBrush(dc
);
583 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
584 DC_vUpdateLineBrush(dc
);
586 pbrFill
= dc
->dclevel
.pbrFill
;
587 pbrLine
= dc
->dclevel
.pbrLine
;
593 psurf
= dc
->dclevel
.pSurface
;
602 if (!(pbrFill
->flAttrs
& GDIBRUSH_IS_NULL
))
604 BrushOrigin
= *((PPOINTL
)&pbrFill
->ptOrigin
);
605 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
606 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
607 ret
= IntEngBitBlt(&psurf
->SurfObj
,
610 dc
->rosdc
.CombinedClip
,
615 &dc
->eboFill
.BrushObject
,
617 ROP3_TO_ROP4(PATCOPY
));
621 // Draw the rectangle with the current pen
623 ret
= TRUE
; // change default to success
625 if (!(pbrLine
->flAttrs
& GDIBRUSH_IS_NULL
))
627 Mix
= ROP2_TO_MIX(pdcattr
->jROP2
);
628 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
629 dc
->rosdc
.CombinedClip
,
630 &dc
->eboLine
.BrushObject
,
631 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
632 &DestRect
, // Bounding rectangle
635 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
636 dc
->rosdc
.CombinedClip
,
637 &dc
->eboLine
.BrushObject
,
638 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
639 &DestRect
, // Bounding rectangle
642 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
643 dc
->rosdc
.CombinedClip
,
644 &dc
->eboLine
.BrushObject
,
645 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
646 &DestRect
, // Bounding rectangle
649 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
650 dc
->rosdc
.CombinedClip
,
651 &dc
->eboLine
.BrushObject
,
652 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
653 &DestRect
, // Bounding rectangle
658 /* Move current position in DC?
659 MSDN: The current position is neither used nor updated by Rectangle. */
666 NtGdiRectangle(HDC hDC
,
673 BOOL ret
; // default to failure
674 RECT rect
= {LeftRect
, TopRect
, RightRect
, BottomRect
} ;
679 SetLastWin32Error(ERROR_INVALID_HANDLE
);
682 if (dc
->dctype
== DC_TYPE_INFO
)
685 /* Yes, Windows really returns TRUE in this case */
689 DC_vPrepareDCsForBlit(dc
, rect
, NULL
, rect
);
690 if (dc
->pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
691 DC_vUpdateFillBrush(dc
);
693 if (dc
->pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
694 DC_vUpdateLineBrush(dc
);
696 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
697 DC_vFinishBlit(dc
, NULL
);
716 PBRUSH pbrushLine
, pbrushFill
;
718 LONG PenWidth
, PenOrigWidth
;
719 BOOL ret
= TRUE
; // default to success
722 ASSERT ( dc
); // caller's responsibility to set this up
724 if ( PATH_IsPathOpen(dc
->dclevel
) )
725 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
726 xCurveDiameter
, yCurveDiameter
);
728 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
730 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
731 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
735 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
739 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
742 pdcattr
= dc
->pdcattr
;
744 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
745 DC_vUpdateFillBrush(dc
);
747 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
748 DC_vUpdateLineBrush(dc
);
750 pbrushLine
= PEN_LockPen(pdcattr
->hpen
);
753 /* Nothing to do, as we don't have a bitmap */
754 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
758 PenOrigWidth
= PenWidth
= pbrushLine
->ptPenWidth
.x
;
759 if (pbrushLine
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
761 if (pbrushLine
->ulPenStyle
== PS_INSIDEFRAME
)
763 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
764 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
765 Left
+= PenWidth
/ 2;
766 Right
-= (PenWidth
- 1) / 2;
768 Bottom
-= (PenWidth
- 1) / 2;
771 if (!PenWidth
) PenWidth
= 1;
772 pbrushLine
->ptPenWidth
.x
= PenWidth
;
774 RectBounds
.left
= Left
;
775 RectBounds
.top
= Top
;
776 RectBounds
.right
= Right
;
777 RectBounds
.bottom
= Bottom
;
779 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
781 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
782 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
783 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
784 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
786 pbrushFill
= BRUSH_LockBrush(pdcattr
->hbrush
);
787 if (NULL
== pbrushFill
)
789 DPRINT1("FillRound Fail\n");
790 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
795 RtlCopyMemory(&brushTemp
, pbrushFill
, sizeof(brushTemp
));
796 brushTemp
.ptOrigin
.x
+= RectBounds
.left
- Left
;
797 brushTemp
.ptOrigin
.y
+= RectBounds
.top
- Top
;
798 ret
= IntFillRoundRect( dc
,
806 BRUSH_UnlockBrush(pbrushFill
);
810 ret
= IntDrawRoundRect( dc
,
819 pbrushLine
->ptPenWidth
.x
= PenOrigWidth
;
820 PEN_UnlockPen(pbrushLine
);
835 DC
*dc
= DC_LockDc(hDC
);
836 BOOL ret
= FALSE
; /* default to failure */
838 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
841 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
842 SetLastWin32Error(ERROR_INVALID_HANDLE
);
844 else if (dc
->dctype
== DC_TYPE_INFO
)
847 /* Yes, Windows really returns TRUE in this case */
852 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
875 HPALETTE hDestPalette
;
883 /* check parameters */
884 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
886 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
888 for (i
= 0; i
< uMesh
; i
++, tr
++)
890 if (tr
->Vertex1
>= uVertex
||
891 tr
->Vertex2
>= uVertex
||
892 tr
->Vertex3
>= uVertex
)
894 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
901 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
902 for (i
= 0; i
< uMesh
; i
++, rc
++)
904 if (rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
906 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
912 /* calculate extent */
913 Extent
.left
= Extent
.right
= pVertex
->x
;
914 Extent
.top
= Extent
.bottom
= pVertex
->y
;
915 for (i
= 0; i
< uVertex
; i
++)
917 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
918 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
919 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
920 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
922 IntLPtoDP(dc
, (LPPOINT
)&Extent
, 2);
924 Extent
.left
+= dc
->ptlDCOrig
.x
;
925 Extent
.right
+= dc
->ptlDCOrig
.x
;
926 Extent
.top
+= dc
->ptlDCOrig
.y
;
927 Extent
.bottom
+= dc
->ptlDCOrig
.y
;
929 DitherOrg
.x
= DitherOrg
.y
= 0;
930 IntLPtoDP(dc
, (LPPOINT
)&DitherOrg
, 1);
932 DitherOrg
.x
+= dc
->ptlDCOrig
.x
;
933 DitherOrg
.y
+= dc
->ptlDCOrig
.y
;
935 psurf
= dc
->dclevel
.pSurface
;
936 /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
939 hDestPalette
= psurf
->hDIBPalette
;
940 if (!hDestPalette
) hDestPalette
= pPrimarySurface
->devinfo
.hpalDefault
;
942 PalDestGDI
= PALETTE_LockPalette(hDestPalette
);
943 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, PalDestGDI
, 0, 0, 0);
945 Ret
= IntEngGradientFill(&psurf
->SurfObj
,
946 dc
->rosdc
.CombinedClip
,
956 EXLATEOBJ_vCleanup(&exlo
);
959 PALETTE_UnlockPalette(PalDestGDI
);
976 PTRIVERTEX SafeVertex
;
979 NTSTATUS Status
= STATUS_SUCCESS
;
984 SetLastWin32Error(ERROR_INVALID_HANDLE
);
987 if (dc
->dctype
== DC_TYPE_INFO
)
990 /* Yes, Windows really returns TRUE in this case */
993 if (!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
996 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1002 case GRADIENT_FILL_RECT_H
:
1003 case GRADIENT_FILL_RECT_V
:
1004 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
1006 case GRADIENT_FILL_TRIANGLE
:
1007 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
1011 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1017 ProbeForRead(pVertex
,
1018 uVertex
* sizeof(TRIVERTEX
),
1024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1026 Status
= _SEH2_GetExceptionCode();
1030 if (!NT_SUCCESS(Status
))
1033 SetLastWin32Error(Status
);
1037 if (!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1040 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1044 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1048 /* pointers were already probed! */
1049 RtlCopyMemory(SafeVertex
,
1051 uVertex
* sizeof(TRIVERTEX
));
1052 RtlCopyMemory(SafeMesh
,
1056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1058 Status
= _SEH2_GetExceptionCode();
1062 if (!NT_SUCCESS(Status
))
1065 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1066 SetLastNtError(Status
);
1070 DC_vPrepareDCsForBlit(dc
, dc
->rosdc
.CombinedClip
->rclBounds
,
1071 NULL
, dc
->rosdc
.CombinedClip
->rclBounds
);
1073 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1075 DC_vFinishBlit(dc
, NULL
) ;
1077 ExFreePool(SafeVertex
);
1091 SURFACE
*psurf
= NULL
;
1100 dc
= DC_LockDc(hDC
);
1103 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1106 if (dc
->dctype
== DC_TYPE_INFO
)
1109 /* Yes, Windows really returns TRUE in this case */
1113 pdcattr
= dc
->pdcattr
;
1115 if (pdcattr
->ulDirty_
& (DIRTY_FILL
| DC_BRUSH_DIRTY
))
1116 DC_vUpdateFillBrush(dc
);
1118 if (pdcattr
->ulDirty_
& (DIRTY_LINE
| DC_PEN_DIRTY
))
1119 DC_vUpdateLineBrush(dc
);
1123 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1125 Ret
= NtGdiPtInRegion(dc
->rosdc
.hGCClipRgn
, Pt
.x
, Pt
.y
);
1127 IntGdiGetRgnBox(dc
->rosdc
.hGCClipRgn
,(LPRECT
)&DestRect
);
1131 psurf
= dc
->dclevel
.pSurface
;
1138 hpal
= dc
->dclevel
.pSurface
->hDIBPalette
;
1139 if (!hpal
) hpal
= pPrimarySurface
->devinfo
.hpalDefault
;
1140 ppal
= PALETTE_ShareLockPalette(hpal
);
1142 EXLATEOBJ_vInitialize(&exlo
, &gpalRGB
, ppal
, 0, 0xffffff, 0);
1144 /* Only solid fills supported for now
1145 * How to support pattern brushes and non standard surfaces (not offering dib functions):
1146 * Version a (most likely slow): call DrvPatBlt for every pixel
1147 * Version b: create a flood mask and let MaskBlt blit a masked brush */
1148 ConvColor
= XLATEOBJ_iXlate(&exlo
.xlo
, Color
);
1149 Ret
= DIB_XXBPP_FloodFillSolid(&psurf
->SurfObj
, &dc
->eboFill
.BrushObject
, &DestRect
, &Pt
, ConvColor
, FillType
);
1151 EXLATEOBJ_vCleanup(&exlo
);
1152 PALETTE_ShareUnlockPalette(ppal
);