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(&psurf->SurfObj, \
31 &BrushInst.BrushObject, \
34 ROP2_TO_MIX(Dc_Attr->jROP2));
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&psurf->SurfObj, \
39 &BrushInst.BrushObject, \
42 ROP2_TO_MIX(Dc_Attr->jROP2));
44 #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
45 #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
47 BOOL FASTCALL
IntFillEllipse( PDC dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PGDIBRUSHOBJ FillBrushObj
);
48 BOOL FASTCALL
IntDrawEllipse( PDC dc
, INT XLeft
, INT YLeft
, INT Width
, INT Height
, PGDIBRUSHOBJ PenBrushObj
);
49 BOOL FASTCALL
IntFillRoundRect( PDC dc
, INT Left
, INT Top
, INT Right
, INT Bottom
, INT Wellipse
, INT Hellipse
, PGDIBRUSHOBJ FillBrushObj
);
50 BOOL FASTCALL
IntDrawRoundRect( PDC dc
, INT Left
, INT Top
, INT Right
, INT Bottom
, INT Wellipse
, INT Hellipse
, PGDIBRUSHOBJ PenBrushObj
);
58 PGDIBRUSHOBJ PenBrushObj
, FillBrushObj
;
59 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
60 BOOL ret
= FALSE
; // default to failure
68 ASSERT(dc
); // caller's responsibility to pass a valid dc
70 if (!Points
|| Count
< 2 )
72 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
80 for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
81 Left = min(Left, Points[CurrentPoint].x);
82 Top = min(Top, Points[CurrentPoint].y);
86 Dc_Attr
= dc
->pDc_Attr
;
87 if (!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
89 /* Convert to screen coordinates */
90 IntLPtoDP(dc
, Points
, Count
);
91 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
93 Points
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
94 Points
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
96 // No need to have path here.
98 DestRect
.left
= Points
[0].x
;
99 DestRect
.right
= Points
[0].x
;
100 DestRect
.top
= Points
[0].y
;
101 DestRect
.bottom
= Points
[0].y
;
103 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
105 DestRect
.left
= min(DestRect
.left
, Points
[CurrentPoint
].x
);
106 DestRect
.right
= max(DestRect
.right
, Points
[CurrentPoint
].x
);
107 DestRect
.top
= min(DestRect
.top
, Points
[CurrentPoint
].y
);
108 DestRect
.bottom
= max(DestRect
.bottom
, Points
[CurrentPoint
].y
);
111 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
112 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
114 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
115 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
117 /* Special locking order to avoid lock-ups */
118 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
119 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
120 psurf
= SURFACE_LockSurface(dc
->rosdc
.hBitmap
);
121 /* FIXME - psurf can be NULL!!!! don't assert but handle this case gracefully! */
124 /* Now fill the polygon with the current brush. */
125 if (FillBrushObj
&& !(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
127 BrushOrigin
= *((PPOINTL
)&FillBrushObj
->ptOrigin
);
128 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
129 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
130 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->rosdc
.XlateBrush
);
131 ret
= IntFillPolygon (dc
, psurf
, &FillBrushInst
.BrushObject
, Points
, Count
,
132 DestRect
, &BrushOrigin
);
135 BRUSHOBJ_UnlockBrush(FillBrushObj
);
137 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
138 if (PenBrushObj
&& !(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
142 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->rosdc
.XlatePen
);
144 for (i
= 0; i
< Count
-1; i
++)
147 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
148 // Points[0].x, Points[0].y,
149 // Points[1].x, Points[1].y );
151 ret
= IntEngLineTo(&psurf
->SurfObj
,
152 dc
->rosdc
.CombinedClip
,
153 &PenBrushInst
.BrushObject
,
154 Points
[i
].x
, /* From */
156 Points
[i
+1].x
, /* To */
159 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
162 /* Close the polygon */
165 ret
= IntEngLineTo(&psurf
->SurfObj
,
166 dc
->rosdc
.CombinedClip
,
167 &PenBrushInst
.BrushObject
,
168 Points
[Count
-1].x
, /* From */
170 Points
[0].x
, /* To */
173 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
177 PENOBJ_UnlockPen(PenBrushObj
);
179 SURFACE_UnlockSurface(psurf
);
185 IntGdiPolyPolygon(DC
*dc
,
190 if (PATH_IsPathOpen(dc
->DcLevel
))
191 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
195 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
197 Points
+=*PolyCounts
++;
204 /******************************************************************************/
213 * This function uses optimized Bresenham's ellipse algorithm. It draws
214 * four lines of the ellipse in one pass.
229 PGDIBRUSHOBJ PenBrushObj
;
231 LONG PenWidth
, PenOrigWidth
;
232 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
233 PGDIBRUSHOBJ pFillBrushObj
;
234 GDIBRUSHOBJ tmpFillBrushObj
;
236 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
241 SetLastWin32Error(ERROR_INVALID_HANDLE
);
244 if (dc
->dctype
== DC_TYPE_INFO
)
247 /* Yes, Windows really returns TRUE in this case */
251 if (PATH_IsPathOpen(dc
->DcLevel
))
253 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
260 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
264 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
267 Dc_Attr
= dc
->pDc_Attr
;
268 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
270 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
271 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
273 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
274 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
276 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
277 if (NULL
== PenBrushObj
)
279 DPRINT1("Ellipse Fail 1\n");
281 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
285 PenOrigWidth
= PenWidth
= PenBrushObj
->ptPenWidth
.x
;
286 if (PenBrushObj
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
288 if (PenBrushObj
->ulPenStyle
== PS_INSIDEFRAME
)
290 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
291 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
292 Left
+= PenWidth
/ 2;
293 Right
-= (PenWidth
- 1) / 2;
295 Bottom
-= (PenWidth
- 1) / 2;
298 if (!PenWidth
) PenWidth
= 1;
299 PenBrushObj
->ptPenWidth
.x
= PenWidth
;
301 RectBounds
.left
= Left
;
302 RectBounds
.right
= Right
;
303 RectBounds
.top
= Top
;
304 RectBounds
.bottom
= Bottom
;
306 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
308 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
309 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
310 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
311 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
313 // Setup for dynamic width and height.
314 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
315 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
316 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
317 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
319 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
320 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
322 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
323 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
325 pFillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
326 if (NULL
== pFillBrushObj
)
328 DPRINT1("FillEllipse Fail\n");
329 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
334 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
335 // tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
336 // tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
337 tmpFillBrushObj
.ptOrigin
.x
+= dc
->ptlDCOrig
.x
;
338 tmpFillBrushObj
.ptOrigin
.y
+= dc
->ptlDCOrig
.y
;
339 ret
= IntFillEllipse( dc
,
345 BRUSHOBJ_UnlockBrush(pFillBrushObj
);
349 ret
= IntDrawEllipse( dc
,
356 PenBrushObj
->ptPenWidth
.x
= PenOrigWidth
;
357 PENOBJ_UnlockPen(PenBrushObj
);
359 DPRINT("Ellipse Exit.\n");
365 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
366 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
367 //first and second side, between the third and fourth side, and so on.
369 //WINDING Selects winding mode (fills any region with a nonzero winding value).
370 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
371 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
372 //The direction of each edge of the polygon is important.
374 extern BOOL
FillPolygon(PDC dc
,
387 NtGdiPolyPolyDraw( IN HDC hDC
,
388 IN PPOINT UnsafePoints
,
389 IN PULONG UnsafeCounts
,
397 NTSTATUS Status
= STATUS_SUCCESS
;
399 INT nPoints
= 0, nMaxPoints
= 0, nInvalid
= 0, i
;
401 if (!UnsafePoints
|| !UnsafeCounts
||
402 Count
== 0 || iFunc
== 0 || iFunc
> GdiPolyPolyRgn
)
404 /* Windows doesn't set last error */
410 ProbeForRead(UnsafePoints
, Count
* sizeof(POINT
), 1);
411 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
413 /* Count points and validate poligons */
414 for (i
= 0; i
< Count
; i
++)
416 if (UnsafeCounts
[i
] < 2)
420 nPoints
+= UnsafeCounts
[i
];
421 nMaxPoints
= max(nMaxPoints
, UnsafeCounts
[i
]);
424 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
426 Status
= _SEH2_GetExceptionCode();
430 if (!NT_SUCCESS(Status
))
432 /* Windows doesn't set last error */
436 if (nPoints
== 0 || nPoints
< nMaxPoints
)
438 /* If all polygon counts are zero, or we have overflow,
439 return without setting a last error code. */
445 /* If at least one poly count is 0 or 1, fail */
446 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
450 /* Allocate one buffer for both counts and points */
451 pTemp
= ExAllocatePoolWithTag(PagedPool
,
452 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
456 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
461 SafePoints
= (PVOID
)(SafeCounts
+ Count
);
465 /* Pointers already probed! */
466 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
467 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
469 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
471 Status
= _SEH2_GetExceptionCode();
475 if (!NT_SUCCESS(Status
))
477 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
481 /* Special handling for GdiPolyPolyRgn */
482 if (iFunc
== GdiPolyPolyRgn
)
485 hRgn
= IntCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, (INT_PTR
)hDC
);
486 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
487 return (ULONG_PTR
)hRgn
;
493 SetLastWin32Error(ERROR_INVALID_HANDLE
);
498 if (dc
->dctype
== DC_TYPE_INFO
)
502 /* Yes, Windows really returns TRUE in this case */
506 /* Perform the actual work */
510 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
512 case GdiPolyPolyLine
:
513 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
516 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
519 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
521 case GdiPolyBezierTo
:
522 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
525 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
529 /* Cleanup and return */
533 return (ULONG_PTR
)Ret
;
545 SURFACE
*psurf
= NULL
;
546 PGDIBRUSHOBJ PenBrushObj
= NULL
, FillBrushObj
= NULL
;
547 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
548 BOOL ret
= FALSE
; // default to failure
554 ASSERT ( dc
); // caller's responsibility to set this up
556 Dc_Attr
= dc
->pDc_Attr
;
557 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
559 /* Do we rotate or shear? */
560 if (!(dc
->DcLevel
.mxWorldToDevice
.flAccel
& MX_SCALE
))
563 POINTL DestCoords
[4];
564 ULONG PolyCounts
= 4;
565 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
566 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
567 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
568 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
569 // Use IntGdiPolyPolygon so to support PATH.
570 return IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
572 // Rectangle Path only.
573 if ( PATH_IsPathOpen(dc
->DcLevel
) )
575 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
578 DestRect
.left
= LeftRect
;
579 DestRect
.right
= RightRect
;
580 DestRect
.top
= TopRect
;
581 DestRect
.bottom
= BottomRect
;
583 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
585 DestRect
.left
+= dc
->ptlDCOrig
.x
;
586 DestRect
.right
+= dc
->ptlDCOrig
.x
;
587 DestRect
.top
+= dc
->ptlDCOrig
.y
;
588 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
590 /* In GM_COMPATIBLE, don't include bottom and right edges */
591 if (IntGetGraphicsMode(dc
) == GM_COMPATIBLE
)
597 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
598 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
600 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
601 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
603 /* Special locking order to avoid lock-ups! */
604 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
605 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
611 psurf
= SURFACE_LockSurface(dc
->rosdc
.hBitmap
);
620 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
622 BrushOrigin
= *((PPOINTL
)&FillBrushObj
->ptOrigin
);
623 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
624 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
625 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->rosdc
.XlateBrush
);
626 ret
= IntEngBitBlt(&psurf
->SurfObj
,
629 dc
->rosdc
.CombinedClip
,
634 &FillBrushInst
.BrushObject
,
636 ROP3_TO_ROP4(PATCOPY
));
640 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->rosdc
.XlatePen
);
642 // Draw the rectangle with the current pen
644 ret
= TRUE
; // change default to success
646 if (!(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
648 Mix
= ROP2_TO_MIX(Dc_Attr
->jROP2
);
649 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
650 dc
->rosdc
.CombinedClip
,
651 &PenBrushInst
.BrushObject
,
652 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
653 &DestRect
, // Bounding rectangle
656 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
657 dc
->rosdc
.CombinedClip
,
658 &PenBrushInst
.BrushObject
,
659 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
660 &DestRect
, // Bounding rectangle
663 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
664 dc
->rosdc
.CombinedClip
,
665 &PenBrushInst
.BrushObject
,
666 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
667 &DestRect
, // Bounding rectangle
670 ret
= ret
&& IntEngLineTo(&psurf
->SurfObj
,
671 dc
->rosdc
.CombinedClip
,
672 &PenBrushInst
.BrushObject
,
673 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
674 &DestRect
, // Bounding rectangle
680 BRUSHOBJ_UnlockBrush(FillBrushObj
);
683 PENOBJ_UnlockPen(PenBrushObj
);
686 SURFACE_UnlockSurface(psurf
);
688 /* Move current position in DC?
689 MSDN: The current position is neither used nor updated by Rectangle. */
696 NtGdiRectangle(HDC hDC
,
703 BOOL ret
; // default to failure
708 SetLastWin32Error(ERROR_INVALID_HANDLE
);
711 if (dc
->dctype
== DC_TYPE_INFO
)
714 /* Yes, Windows really returns TRUE in this case */
718 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
737 PGDIBRUSHOBJ PenBrushObj
;
739 LONG PenWidth
, PenOrigWidth
;
740 BOOL ret
= TRUE
; // default to success
741 PGDIBRUSHOBJ pFillBrushObj
;
742 GDIBRUSHOBJ tmpFillBrushObj
;
744 ASSERT ( dc
); // caller's responsibility to set this up
746 if ( PATH_IsPathOpen(dc
->DcLevel
) )
747 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
748 xCurveDiameter
, yCurveDiameter
);
750 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
752 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
753 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
757 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
761 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
764 Dc_Attr
= dc
->pDc_Attr
;
765 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
767 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
768 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
770 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
771 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
773 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
776 /* Nothing to do, as we don't have a bitmap */
777 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
781 PenOrigWidth
= PenWidth
= PenBrushObj
->ptPenWidth
.x
;
782 if (PenBrushObj
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
784 if (PenBrushObj
->ulPenStyle
== PS_INSIDEFRAME
)
786 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
787 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
788 Left
+= PenWidth
/ 2;
789 Right
-= (PenWidth
- 1) / 2;
791 Bottom
-= (PenWidth
- 1) / 2;
794 if (!PenWidth
) PenWidth
= 1;
795 PenBrushObj
->ptPenWidth
.x
= PenWidth
;
797 RectBounds
.left
= Left
;
798 RectBounds
.top
= Top
;
799 RectBounds
.right
= Right
;
800 RectBounds
.bottom
= Bottom
;
802 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
804 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
805 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
806 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
807 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
809 pFillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
810 if (NULL
== pFillBrushObj
)
812 DPRINT1("FillRound Fail\n");
813 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
818 RtlCopyMemory(&tmpFillBrushObj
, pFillBrushObj
, sizeof(tmpFillBrushObj
));
819 tmpFillBrushObj
.ptOrigin
.x
+= RectBounds
.left
- Left
;
820 tmpFillBrushObj
.ptOrigin
.y
+= RectBounds
.top
- Top
;
821 ret
= IntFillRoundRect( dc
,
829 BRUSHOBJ_UnlockBrush(pFillBrushObj
);
833 ret
= IntDrawRoundRect( dc
,
842 PenBrushObj
->ptPenWidth
.x
= PenOrigWidth
;
843 PENOBJ_UnlockPen(PenBrushObj
);
858 DC
*dc
= DC_LockDc(hDC
);
859 BOOL ret
= FALSE
; /* default to failure */
861 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
864 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
865 SetLastWin32Error(ERROR_INVALID_HANDLE
);
867 else if (dc
->dctype
== DC_TYPE_INFO
)
870 /* Yes, Windows really returns TRUE in this case */
875 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
898 HPALETTE hDestPalette
;
906 /* check parameters */
907 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
909 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
911 for (i
= 0; i
< uMesh
; i
++, tr
++)
913 if (tr
->Vertex1
>= uVertex
||
914 tr
->Vertex2
>= uVertex
||
915 tr
->Vertex3
>= uVertex
)
917 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
924 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
925 for (i
= 0; i
< uMesh
; i
++, rc
++)
927 if (rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
929 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
935 /* calculate extent */
936 Extent
.left
= Extent
.right
= pVertex
->x
;
937 Extent
.top
= Extent
.bottom
= pVertex
->y
;
938 for (i
= 0; i
< uVertex
; i
++)
940 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
941 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
942 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
943 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
946 DitherOrg
.x
= dc
->ptlDCOrig
.x
;
947 DitherOrg
.y
= dc
->ptlDCOrig
.y
;
948 Extent
.left
+= DitherOrg
.x
;
949 Extent
.right
+= DitherOrg
.x
;
950 Extent
.top
+= DitherOrg
.y
;
951 Extent
.bottom
+= DitherOrg
.y
;
953 psurf
= SURFACE_LockSurface(dc
->rosdc
.hBitmap
);
954 /* FIXME - psurf can be NULL!!! Don't assert but handle this case gracefully! */
957 hDestPalette
= psurf
->hDIBPalette
;
958 if (!hDestPalette
) hDestPalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
960 PalDestGDI
= PALETTE_LockPalette(hDestPalette
);
963 Mode
= PalDestGDI
->Mode
;
964 PALETTE_UnlockPalette(PalDestGDI
);
969 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(Mode
, PAL_RGB
, hDestPalette
, NULL
);
972 Ret
= IntEngGradientFill(&psurf
->SurfObj
,
973 dc
->rosdc
.CombinedClip
,
983 SURFACE_UnlockSurface(psurf
);
984 EngDeleteXlate(XlateObj
);
1001 PTRIVERTEX SafeVertex
;
1004 NTSTATUS Status
= STATUS_SUCCESS
;
1006 dc
= DC_LockDc(hdc
);
1009 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1012 if (dc
->dctype
== DC_TYPE_INFO
)
1015 /* Yes, Windows really returns TRUE in this case */
1018 if (!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
1021 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1027 case GRADIENT_FILL_RECT_H
:
1028 case GRADIENT_FILL_RECT_V
:
1029 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
1031 case GRADIENT_FILL_TRIANGLE
:
1032 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
1036 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
1042 ProbeForRead(pVertex
,
1043 uVertex
* sizeof(TRIVERTEX
),
1049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1051 Status
= _SEH2_GetExceptionCode();
1055 if (!NT_SUCCESS(Status
))
1058 SetLastWin32Error(Status
);
1062 if (!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1065 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1069 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1073 /* pointers were already probed! */
1074 RtlCopyMemory(SafeVertex
,
1076 uVertex
* sizeof(TRIVERTEX
));
1077 RtlCopyMemory(SafeMesh
,
1081 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1083 Status
= _SEH2_GetExceptionCode();
1087 if (!NT_SUCCESS(Status
))
1090 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1091 SetLastNtError(Status
);
1095 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1098 ExFreePool(SafeVertex
);
1112 SURFACE
*psurf
= NULL
;
1113 PGDIBRUSHOBJ FillBrushObj
= NULL
;
1114 GDIBRUSHINST FillBrushInst
;
1120 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1122 dc
= DC_LockDc(hDC
);
1125 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1128 if (dc
->dctype
== DC_TYPE_INFO
)
1131 /* Yes, Windows really returns TRUE in this case */
1135 Dc_Attr
= dc
->pDc_Attr
;
1136 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1138 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
1139 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
1141 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
1142 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
1146 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1148 Ret
= NtGdiPtInRegion(dc
->rosdc
.hGCClipRgn
, Pt
.x
, Pt
.y
);
1150 IntGdiGetRgnBox(dc
->rosdc
.hGCClipRgn
,(LPRECT
)&DestRect
);
1154 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1160 psurf
= SURFACE_LockSurface(dc
->rosdc
.hBitmap
);
1167 if ( FillBrushObj
&& (FillType
== FLOODFILLBORDER
))
1169 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1171 FillBrushObj
->BrushAttr
.lbColor
= Color
;
1172 BrushOrigin
= *((PPOINTL
)&FillBrushObj
->ptOrigin
);
1173 BrushOrigin
.x
+= dc
->ptlDCOrig
.x
;
1174 BrushOrigin
.y
+= dc
->ptlDCOrig
.y
;
1175 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->rosdc
.XlateBrush
);
1176 Ret
= IntEngBitBlt(&psurf
->SurfObj
, NULL
, NULL
,
1177 dc
->rosdc
.CombinedClip
, NULL
,
1178 &DestRect
, NULL
, NULL
,
1179 &FillBrushInst
.BrushObject
,
1181 ROP3_TO_ROP4(PATCOPY
));
1190 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1193 SURFACE_UnlockSurface(psurf
);