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(&BitmapObj->SurfObj, \
31 &BrushInst.BrushObject, \
34 ROP2_TO_MIX(Dc_Attr->jROP2));
36 #define PUTLINE(x1,y1,x2,y2,BrushInst) \
37 ret = ret && IntEngLineTo(&BitmapObj->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
);
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
);
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
65 ASSERT(dc
); // caller's responsibility to pass a valid dc
67 if (!Points
|| Count
< 2 )
69 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
73 Dc_Attr
= dc
->pDc_Attr
;
74 if (!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
76 /* Convert to screen coordinates */
77 IntLPtoDP(dc
, Points
, Count
);
78 for (CurrentPoint
= 0; CurrentPoint
< Count
; CurrentPoint
++)
80 Points
[CurrentPoint
].x
+= dc
->ptlDCOrig
.x
;
81 Points
[CurrentPoint
].y
+= dc
->ptlDCOrig
.y
;
83 // No need to have path here.
85 DestRect
.left
= Points
[0].x
;
86 DestRect
.right
= Points
[0].x
;
87 DestRect
.top
= Points
[0].y
;
88 DestRect
.bottom
= Points
[0].y
;
90 for (CurrentPoint
= 1; CurrentPoint
< Count
; ++CurrentPoint
)
92 DestRect
.left
= min(DestRect
.left
, Points
[CurrentPoint
].x
);
93 DestRect
.right
= max(DestRect
.right
, Points
[CurrentPoint
].x
);
94 DestRect
.top
= min(DestRect
.top
, Points
[CurrentPoint
].y
);
95 DestRect
.bottom
= max(DestRect
.bottom
, Points
[CurrentPoint
].y
);
98 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
99 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
101 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
102 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
104 /* Special locking order to avoid lock-ups */
105 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
106 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
107 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
108 /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
111 /* Now fill the polygon with the current brush. */
112 if (FillBrushObj
&& !(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
114 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
115 ret
= FillPolygon ( dc
, BitmapObj
, &FillBrushInst
.BrushObject
, ROP2_TO_MIX(Dc_Attr
->jROP2
), Points
, Count
, DestRect
);
118 BRUSHOBJ_UnlockBrush(FillBrushObj
);
120 // Draw the Polygon Edges with the current pen ( if not a NULL pen )
121 if (PenBrushObj
&& !(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
125 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
127 for (i
= 0; i
< Count
-1; i
++)
130 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
131 // Points[0].x, Points[0].y,
132 // Points[1].x, Points[1].y );
134 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
136 &PenBrushInst
.BrushObject
,
137 Points
[i
].x
, /* From */
139 Points
[i
+1].x
, /* To */
142 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
145 /* Close the polygon */
148 ret
= IntEngLineTo(&BitmapObj
->SurfObj
,
150 &PenBrushInst
.BrushObject
,
151 Points
[Count
-1].x
, /* From */
153 Points
[0].x
, /* To */
156 ROP2_TO_MIX(Dc_Attr
->jROP2
)); /* MIX */
160 PENOBJ_UnlockPen(PenBrushObj
);
162 BITMAPOBJ_UnlockBitmap(BitmapObj
);
168 IntGdiPolyPolygon(DC
*dc
,
173 if (PATH_IsPathOpen(dc
->DcLevel
))
174 return PATH_PolyPolygon ( dc
, Points
, (PINT
)PolyCounts
, Count
);
178 if (!IntGdiPolygon ( dc
, Points
, *PolyCounts
))
180 Points
+=*PolyCounts
++;
187 /******************************************************************************/
196 * This function uses optimized Bresenham's ellipse algorithm. It draws
197 * four lines of the ellipse in one pass.
212 PGDIBRUSHOBJ PenBrushObj
;
214 LONG PenWidth
, PenOrigWidth
;
215 LONG RadiusX
, RadiusY
, CenterX
, CenterY
;
217 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
222 SetLastWin32Error(ERROR_INVALID_HANDLE
);
225 if (dc
->DC_Type
== DC_TYPE_INFO
)
228 /* Yes, Windows really returns TRUE in this case */
232 if (PATH_IsPathOpen(dc
->DcLevel
))
234 ret
= PATH_Ellipse(dc
, Left
, Top
, Right
, Bottom
);
241 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
245 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
248 Dc_Attr
= dc
->pDc_Attr
;
249 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
251 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
252 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
254 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
255 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
257 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
258 if (NULL
== PenBrushObj
)
260 DPRINT1("Ellipse Fail 1\n");
262 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
266 PenOrigWidth
= PenWidth
= PenBrushObj
->ptPenWidth
.x
;
267 if (PenBrushObj
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
269 if (PenBrushObj
->ulPenStyle
== PS_INSIDEFRAME
)
271 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
272 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
273 Left
+= PenWidth
/ 2;
274 Right
-= (PenWidth
- 1) / 2;
276 Bottom
-= (PenWidth
- 1) / 2;
279 if (!PenWidth
) PenWidth
= 1;
280 PenBrushObj
->ptPenWidth
.x
= PenWidth
;
282 RectBounds
.left
= Left
;
283 RectBounds
.right
= Right
;
284 RectBounds
.top
= Top
;
285 RectBounds
.bottom
= Bottom
;
287 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
289 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
290 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
291 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
292 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
294 // Setup for dynamic width and height.
295 RadiusX
= max((RectBounds
.right
- RectBounds
.left
) / 2, 2); // Needs room
296 RadiusY
= max((RectBounds
.bottom
- RectBounds
.top
) / 2, 2);
297 CenterX
= (RectBounds
.right
+ RectBounds
.left
) / 2;
298 CenterY
= (RectBounds
.bottom
+ RectBounds
.top
) / 2;
300 DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
301 RectBounds
.left
,RectBounds
.top
,RectBounds
.right
,RectBounds
.bottom
);
303 DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
304 CenterX
- RadiusX
, CenterY
+ RadiusY
, RadiusX
*2, RadiusY
*2);
306 ret
= IntFillEllipse( dc
,
310 RadiusY
*2); // Height
312 ret
= IntDrawEllipse( dc
,
319 PenBrushObj
->ptPenWidth
.x
= PenOrigWidth
;
320 PENOBJ_UnlockPen(PenBrushObj
);
322 DPRINT("Ellipse Exit.\n");
328 //When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
329 //even-numbered polygon sides on each scan line. That is, GDI fills the area between the
330 //first and second side, between the third and fourth side, and so on.
332 //WINDING Selects winding mode (fills any region with a nonzero winding value).
333 //When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
334 //This value is defined as the number of times a pen used to draw the polygon would go around the region.
335 //The direction of each edge of the polygon is important.
337 extern BOOL
FillPolygon(PDC dc
,
350 NtGdiPolyPolyDraw( IN HDC hDC
,
351 IN PPOINT UnsafePoints
,
352 IN PULONG UnsafeCounts
,
360 NTSTATUS Status
= STATUS_SUCCESS
;
362 INT nPoints
= 0, nMaxPoints
= 0, nInvalid
= 0, i
;
364 if (!UnsafePoints
|| !UnsafeCounts
||
365 Count
== 0 || iFunc
== 0 || iFunc
> GdiPolyPolyRgn
)
367 /* Windows doesn't set last error */
373 ProbeForRead(UnsafePoints
, Count
* sizeof(POINT
), 1);
374 ProbeForRead(UnsafeCounts
, Count
* sizeof(ULONG
), 1);
376 /* Count points and validate poligons */
377 for (i
= 0; i
< Count
; i
++)
379 if (UnsafeCounts
[i
] < 2)
383 nPoints
+= UnsafeCounts
[i
];
384 nMaxPoints
= max(nMaxPoints
, UnsafeCounts
[i
]);
387 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
389 Status
= _SEH2_GetExceptionCode();
393 if (!NT_SUCCESS(Status
))
395 /* Windows doesn't set last error */
399 if (nPoints
== 0 || nPoints
< nMaxPoints
)
401 /* If all polygon counts are zero, or we have overflow,
402 return without setting a last error code. */
408 /* If at least one poly count is 0 or 1, fail */
409 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
413 /* Allocate one buffer for both counts and points */
414 pTemp
= ExAllocatePoolWithTag(PagedPool
,
415 Count
* sizeof(ULONG
) + nPoints
* sizeof(POINT
),
419 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
424 SafePoints
= (PVOID
)(SafeCounts
+ Count
);
428 /* Pointers already probed! */
429 RtlCopyMemory(SafeCounts
, UnsafeCounts
, Count
* sizeof(ULONG
));
430 RtlCopyMemory(SafePoints
, UnsafePoints
, nPoints
* sizeof(POINT
));
432 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
434 Status
= _SEH2_GetExceptionCode();
438 if (!NT_SUCCESS(Status
))
440 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
444 /* Special handling for GdiPolyPolyRgn */
445 if (iFunc
== GdiPolyPolyRgn
)
448 hRgn
= IntCreatePolyPolygonRgn(SafePoints
, SafeCounts
, Count
, (INT_PTR
)hDC
);
449 ExFreePoolWithTag(pTemp
, TAG_SHAPE
);
450 return (ULONG_PTR
)hRgn
;
456 SetLastWin32Error(ERROR_INVALID_HANDLE
);
461 if (dc
->DC_Type
== DC_TYPE_INFO
)
465 /* Yes, Windows really returns TRUE in this case */
469 /* Perform the actual work */
473 Ret
= IntGdiPolyPolygon(dc
, SafePoints
, SafeCounts
, Count
);
475 case GdiPolyPolyLine
:
476 Ret
= IntGdiPolyPolyline(dc
, SafePoints
, SafeCounts
, Count
);
479 Ret
= IntGdiPolyBezier(dc
, SafePoints
, *SafeCounts
);
482 Ret
= IntGdiPolylineTo(dc
, SafePoints
, *SafeCounts
);
484 case GdiPolyBezierTo
:
485 Ret
= IntGdiPolyBezierTo(dc
, SafePoints
, *SafeCounts
);
488 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
492 /* Cleanup and return */
496 return (ULONG_PTR
)Ret
;
508 BITMAPOBJ
*BitmapObj
= NULL
;
509 PGDIBRUSHOBJ PenBrushObj
= NULL
, FillBrushObj
= NULL
;
510 GDIBRUSHINST PenBrushInst
, FillBrushInst
;
511 BOOL ret
= FALSE
; // default to failure
516 ASSERT ( dc
); // caller's responsibility to set this up
518 Dc_Attr
= dc
->pDc_Attr
;
519 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
521 /* Do we rotate or shear? */
522 if (!(dc
->DcLevel
.mxWorldToDevice
.flAccel
& MX_SCALE
))
525 POINTL DestCoords
[4];
526 ULONG PolyCounts
= 4;
527 DestCoords
[0].x
= DestCoords
[3].x
= LeftRect
;
528 DestCoords
[0].y
= DestCoords
[1].y
= TopRect
;
529 DestCoords
[1].x
= DestCoords
[2].x
= RightRect
;
530 DestCoords
[2].y
= DestCoords
[3].y
= BottomRect
;
531 // Use IntGdiPolyPolygon so to support PATH.
532 return IntGdiPolyPolygon(dc
, DestCoords
, &PolyCounts
, 1);
534 // Rectangle Path only.
535 if ( PATH_IsPathOpen(dc
->DcLevel
) )
537 return PATH_Rectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
540 DestRect
.left
= LeftRect
;
541 DestRect
.right
= RightRect
;
542 DestRect
.top
= TopRect
;
543 DestRect
.bottom
= BottomRect
;
545 IntLPtoDP(dc
, (LPPOINT
)&DestRect
, 2);
547 DestRect
.left
+= dc
->ptlDCOrig
.x
;
548 DestRect
.right
+= dc
->ptlDCOrig
.x
;
549 DestRect
.top
+= dc
->ptlDCOrig
.y
;
550 DestRect
.bottom
+= dc
->ptlDCOrig
.y
;
552 /* In GM_COMPATIBLE, don't include bottom and right edges */
553 if (IntGetGraphicsMode(dc
) == GM_COMPATIBLE
)
559 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
560 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
562 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
563 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
565 /* Special locking order to avoid lock-ups! */
566 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
567 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
573 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
582 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
584 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
585 ret
= IntEngBitBlt(&BitmapObj
->SurfObj
,
593 &FillBrushInst
.BrushObject
,
595 ROP3_TO_ROP4(PATCOPY
));
599 IntGdiInitBrushInstance(&PenBrushInst
, PenBrushObj
, dc
->XlatePen
);
601 // Draw the rectangle with the current pen
603 ret
= TRUE
; // change default to success
605 if (!(PenBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
607 Mix
= ROP2_TO_MIX(Dc_Attr
->jROP2
);
608 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
610 &PenBrushInst
.BrushObject
,
611 DestRect
.left
, DestRect
.top
, DestRect
.right
, DestRect
.top
,
612 &DestRect
, // Bounding rectangle
615 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
617 &PenBrushInst
.BrushObject
,
618 DestRect
.right
, DestRect
.top
, DestRect
.right
, DestRect
.bottom
,
619 &DestRect
, // Bounding rectangle
622 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
624 &PenBrushInst
.BrushObject
,
625 DestRect
.right
, DestRect
.bottom
, DestRect
.left
, DestRect
.bottom
,
626 &DestRect
, // Bounding rectangle
629 ret
= ret
&& IntEngLineTo(&BitmapObj
->SurfObj
,
631 &PenBrushInst
.BrushObject
,
632 DestRect
.left
, DestRect
.bottom
, DestRect
.left
, DestRect
.top
,
633 &DestRect
, // Bounding rectangle
639 BRUSHOBJ_UnlockBrush(FillBrushObj
);
642 PENOBJ_UnlockPen(PenBrushObj
);
645 BITMAPOBJ_UnlockBitmap(BitmapObj
);
647 /* Move current position in DC?
648 MSDN: The current position is neither used nor updated by Rectangle. */
655 NtGdiRectangle(HDC hDC
,
662 BOOL ret
; // default to failure
667 SetLastWin32Error(ERROR_INVALID_HANDLE
);
670 if (dc
->DC_Type
== DC_TYPE_INFO
)
673 /* Yes, Windows really returns TRUE in this case */
677 ret
= IntRectangle ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
);
696 PGDIBRUSHOBJ PenBrushObj
;
698 LONG PenWidth
, PenOrigWidth
;
699 BOOL ret
= TRUE
; // default to success
701 ASSERT ( dc
); // caller's responsibility to set this up
703 if ( PATH_IsPathOpen(dc
->DcLevel
) )
704 return PATH_RoundRect ( dc
, Left
, Top
, Right
, Bottom
,
705 xCurveDiameter
, yCurveDiameter
);
707 if ((Left
== Right
) || (Top
== Bottom
)) return TRUE
;
709 xCurveDiameter
= max(abs( xCurveDiameter
), 1);
710 yCurveDiameter
= max(abs( yCurveDiameter
), 1);
714 INT tmp
= Right
; Right
= Left
; Left
= tmp
;
718 INT tmp
= Bottom
; Bottom
= Top
; Top
= tmp
;
721 Dc_Attr
= dc
->pDc_Attr
;
722 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
724 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
725 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
727 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
728 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
730 PenBrushObj
= PENOBJ_LockPen(Dc_Attr
->hpen
);
733 /* Nothing to do, as we don't have a bitmap */
734 SetLastWin32Error(ERROR_INTERNAL_ERROR
);
738 PenOrigWidth
= PenWidth
= PenBrushObj
->ptPenWidth
.x
;
739 if (PenBrushObj
->ulPenStyle
== PS_NULL
) PenWidth
= 0;
741 if (PenBrushObj
->ulPenStyle
== PS_INSIDEFRAME
)
743 if (2*PenWidth
> (Right
- Left
)) PenWidth
= (Right
-Left
+ 1)/2;
744 if (2*PenWidth
> (Bottom
- Top
)) PenWidth
= (Bottom
-Top
+ 1)/2;
745 Left
+= PenWidth
/ 2;
746 Right
-= (PenWidth
- 1) / 2;
748 Bottom
-= (PenWidth
- 1) / 2;
751 if (!PenWidth
) PenWidth
= 1;
752 PenBrushObj
->ptPenWidth
.x
= PenWidth
;
754 RectBounds
.left
= Left
;
755 RectBounds
.top
= Top
;
756 RectBounds
.right
= Right
;
757 RectBounds
.bottom
= Bottom
;
759 IntLPtoDP(dc
, (LPPOINT
)&RectBounds
, 2);
761 RectBounds
.left
+= dc
->ptlDCOrig
.x
;
762 RectBounds
.top
+= dc
->ptlDCOrig
.y
;
763 RectBounds
.right
+= dc
->ptlDCOrig
.x
;
764 RectBounds
.bottom
+= dc
->ptlDCOrig
.y
;
766 ret
= IntFillRoundRect( dc
,
774 ret
= IntDrawRoundRect( dc
,
783 PenBrushObj
->ptPenWidth
.x
= PenOrigWidth
;
784 PENOBJ_UnlockPen(PenBrushObj
);
799 DC
*dc
= DC_LockDc(hDC
);
800 BOOL ret
= FALSE
; /* default to failure */
802 DPRINT("NtGdiRoundRect(0x%x,%i,%i,%i,%i,%i,%i)\n",hDC
,LeftRect
,TopRect
,RightRect
,BottomRect
,Width
,Height
);
805 DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
806 SetLastWin32Error(ERROR_INVALID_HANDLE
);
808 else if (dc
->DC_Type
== DC_TYPE_INFO
)
811 /* Yes, Windows really returns TRUE in this case */
816 ret
= IntRoundRect ( dc
, LeftRect
, TopRect
, RightRect
, BottomRect
, Width
, Height
);
832 BITMAPOBJ
*BitmapObj
;
839 HPALETTE hDestPalette
;
847 /* check parameters */
848 if (ulMode
& GRADIENT_FILL_TRIANGLE
)
850 PGRADIENT_TRIANGLE tr
= (PGRADIENT_TRIANGLE
)pMesh
;
852 for (i
= 0; i
< uMesh
; i
++, tr
++)
854 if (tr
->Vertex1
>= uVertex
||
855 tr
->Vertex2
>= uVertex
||
856 tr
->Vertex3
>= uVertex
)
858 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
865 PGRADIENT_RECT rc
= (PGRADIENT_RECT
)pMesh
;
866 for (i
= 0; i
< uMesh
; i
++, rc
++)
868 if (rc
->UpperLeft
>= uVertex
|| rc
->LowerRight
>= uVertex
)
870 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
876 /* calculate extent */
877 Extent
.left
= Extent
.right
= pVertex
->x
;
878 Extent
.top
= Extent
.bottom
= pVertex
->y
;
879 for (i
= 0; i
< uVertex
; i
++)
881 Extent
.left
= min(Extent
.left
, (pVertex
+ i
)->x
);
882 Extent
.right
= max(Extent
.right
, (pVertex
+ i
)->x
);
883 Extent
.top
= min(Extent
.top
, (pVertex
+ i
)->y
);
884 Extent
.bottom
= max(Extent
.bottom
, (pVertex
+ i
)->y
);
887 DitherOrg
.x
= dc
->ptlDCOrig
.x
;
888 DitherOrg
.y
= dc
->ptlDCOrig
.y
;
889 Extent
.left
+= DitherOrg
.x
;
890 Extent
.right
+= DitherOrg
.x
;
891 Extent
.top
+= DitherOrg
.y
;
892 Extent
.bottom
+= DitherOrg
.y
;
894 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
895 /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
898 hDestPalette
= BitmapObj
->hDIBPalette
;
899 if (!hDestPalette
) hDestPalette
= pPrimarySurface
->DevInfo
.hpalDefault
;
901 PalDestGDI
= PALETTE_LockPalette(hDestPalette
);
904 Mode
= PalDestGDI
->Mode
;
905 PALETTE_UnlockPalette(PalDestGDI
);
910 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate(Mode
, PAL_RGB
, hDestPalette
, NULL
);
913 Ret
= IntEngGradientFill(&BitmapObj
->SurfObj
,
924 BITMAPOBJ_UnlockBitmap(BitmapObj
);
925 EngDeleteXlate(XlateObj
);
942 PTRIVERTEX SafeVertex
;
945 NTSTATUS Status
= STATUS_SUCCESS
;
950 SetLastWin32Error(ERROR_INVALID_HANDLE
);
953 if (dc
->DC_Type
== DC_TYPE_INFO
)
956 /* Yes, Windows really returns TRUE in this case */
959 if (!pVertex
|| !uVertex
|| !pMesh
|| !uMesh
)
962 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
968 case GRADIENT_FILL_RECT_H
:
969 case GRADIENT_FILL_RECT_V
:
970 SizeMesh
= uMesh
* sizeof(GRADIENT_RECT
);
972 case GRADIENT_FILL_TRIANGLE
:
973 SizeMesh
= uMesh
* sizeof(TRIVERTEX
);
977 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
983 ProbeForRead(pVertex
,
984 uVertex
* sizeof(TRIVERTEX
),
990 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
992 Status
= _SEH2_GetExceptionCode();
996 if (!NT_SUCCESS(Status
))
999 SetLastWin32Error(Status
);
1003 if (!(SafeVertex
= ExAllocatePoolWithTag(PagedPool
, (uVertex
* sizeof(TRIVERTEX
)) + SizeMesh
, TAG_SHAPE
)))
1006 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY
);
1010 SafeMesh
= (PTRIVERTEX
)(SafeVertex
+ uVertex
);
1014 /* pointers were already probed! */
1015 RtlCopyMemory(SafeVertex
,
1017 uVertex
* sizeof(TRIVERTEX
));
1018 RtlCopyMemory(SafeMesh
,
1022 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1024 Status
= _SEH2_GetExceptionCode();
1028 if (!NT_SUCCESS(Status
))
1031 ExFreePoolWithTag(SafeVertex
, TAG_SHAPE
);
1032 SetLastNtError(Status
);
1036 Ret
= IntGdiGradientFill(dc
, SafeVertex
, uVertex
, SafeMesh
, uMesh
, ulMode
);
1039 ExFreePool(SafeVertex
);
1053 BITMAPOBJ
*BitmapObj
= NULL
;
1054 PGDIBRUSHOBJ FillBrushObj
= NULL
;
1055 GDIBRUSHINST FillBrushInst
;
1061 DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
1063 dc
= DC_LockDc(hDC
);
1066 SetLastWin32Error(ERROR_INVALID_HANDLE
);
1069 if (dc
->DC_Type
== DC_TYPE_INFO
)
1072 /* Yes, Windows really returns TRUE in this case */
1076 Dc_Attr
= dc
->pDc_Attr
;
1077 if(!Dc_Attr
) Dc_Attr
= &dc
->Dc_Attr
;
1079 if (Dc_Attr
->ulDirty_
& DC_PEN_DIRTY
)
1080 IntGdiSelectPen(dc
,Dc_Attr
->hpen
);
1082 if (Dc_Attr
->ulDirty_
& DC_BRUSH_DIRTY
)
1083 IntGdiSelectBrush(dc
,Dc_Attr
->hbrush
);
1087 IntLPtoDP(dc
, (LPPOINT
)&Pt
, 1);
1089 Ret
= NtGdiPtInRegion(dc
->w
.hGCClipRgn
, Pt
.x
, Pt
.y
);
1091 IntGdiGetRgnBox(dc
->w
.hGCClipRgn
,(LPRECT
)&DestRect
);
1095 FillBrushObj
= BRUSHOBJ_LockBrush(Dc_Attr
->hbrush
);
1101 BitmapObj
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
1108 if ( FillBrushObj
&& (FillType
== FLOODFILLBORDER
))
1110 if (!(FillBrushObj
->flAttrs
& GDIBRUSH_IS_NULL
))
1112 FillBrushObj
->BrushAttr
.lbColor
= Color
;
1113 IntGdiInitBrushInstance(&FillBrushInst
, FillBrushObj
, dc
->XlateBrush
);
1114 Ret
= IntEngBitBlt(&BitmapObj
->SurfObj
,
1122 &FillBrushInst
.BrushObject
,
1124 ROP3_TO_ROP4(PATCOPY
));
1133 BRUSHOBJ_UnlockBrush(FillBrushObj
);
1136 BITMAPOBJ_UnlockBitmap(BitmapObj
);