xref: /reactos/win32ss/gdi/ntgdi/fillshap.c (revision 94b4b5c1)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS win32 kernel mode subsystem
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            win32ss/gdi/ntgdi/fillshap.c
5c2c66affSColin Finck  * PURPOSE:         fillshap
6c2c66affSColin Finck  * PROGRAMMER:
7c2c66affSColin Finck  */
8c2c66affSColin Finck 
9c2c66affSColin Finck #include <win32k.h>
10c2c66affSColin Finck 
11c2c66affSColin Finck #define NDEBUG
12c2c66affSColin Finck #include <debug.h>
13c2c66affSColin Finck 
14c2c66affSColin Finck #define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
15c2c66affSColin Finck #define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
16c2c66affSColin Finck 
17c2c66affSColin Finck BOOL FASTCALL
18c2c66affSColin Finck IntGdiPolygon(PDC    dc,
19c2c66affSColin Finck               PPOINT Points,
20c2c66affSColin Finck               int    Count)
21c2c66affSColin Finck {
22c2c66affSColin Finck     SURFACE *psurf;
23c2c66affSColin Finck     PBRUSH pbrLine, pbrFill;
24c2c66affSColin Finck     BOOL ret = FALSE; // Default to failure
25c2c66affSColin Finck     RECTL DestRect;
26c2c66affSColin Finck     int CurrentPoint;
27c2c66affSColin Finck     PDC_ATTR pdcattr;
28c2c66affSColin Finck     POINTL BrushOrigin;
29c2c66affSColin Finck //    int Left;
30c2c66affSColin Finck //    int Top;
31c2c66affSColin Finck 
32c2c66affSColin Finck     ASSERT(dc); // Caller's responsibility to pass a valid dc
33c2c66affSColin Finck 
34c2c66affSColin Finck     if (!Points || Count < 2 )
35c2c66affSColin Finck     {
36c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_PARAMETER);
37c2c66affSColin Finck         return FALSE;
38c2c66affSColin Finck     }
39c2c66affSColin Finck 
40c2c66affSColin Finck /*
41c2c66affSColin Finck     // Find start x, y
42c2c66affSColin Finck     Left = Points[0].x;
43c2c66affSColin Finck     Top  = Points[0].y;
44c2c66affSColin Finck     for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
45c2c66affSColin Finck       Left = min(Left, Points[CurrentPoint].x);
46c2c66affSColin Finck       Top  = min(Top, Points[CurrentPoint].y);
47c2c66affSColin Finck     }
48c2c66affSColin Finck */
49c2c66affSColin Finck 
50c2c66affSColin Finck     pdcattr = dc->pdcattr;
51c2c66affSColin Finck 
52c2c66affSColin Finck     /* Convert to screen coordinates */
53c2c66affSColin Finck     IntLPtoDP(dc, Points, Count);
54c2c66affSColin Finck     for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
55c2c66affSColin Finck     {
56c2c66affSColin Finck         Points[CurrentPoint].x += dc->ptlDCOrig.x;
57c2c66affSColin Finck         Points[CurrentPoint].y += dc->ptlDCOrig.y;
58c2c66affSColin Finck     }
59c2c66affSColin Finck     // No need to have path here.
60c2c66affSColin Finck     {
61c2c66affSColin Finck         DestRect.left   = Points[0].x;
62c2c66affSColin Finck         DestRect.right  = Points[0].x;
63c2c66affSColin Finck         DestRect.top    = Points[0].y;
64c2c66affSColin Finck         DestRect.bottom = Points[0].y;
65c2c66affSColin Finck 
66c2c66affSColin Finck         for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
67c2c66affSColin Finck         {
68c2c66affSColin Finck             DestRect.left     = min(DestRect.left, Points[CurrentPoint].x);
69c2c66affSColin Finck             DestRect.right    = max(DestRect.right, Points[CurrentPoint].x);
70c2c66affSColin Finck             DestRect.top      = min(DestRect.top, Points[CurrentPoint].y);
71c2c66affSColin Finck             DestRect.bottom   = max(DestRect.bottom, Points[CurrentPoint].y);
72c2c66affSColin Finck         }
73c2c66affSColin Finck 
74c2c66affSColin Finck         if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
75c2c66affSColin Finck             DC_vUpdateFillBrush(dc);
76c2c66affSColin Finck 
77c2c66affSColin Finck         if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
78c2c66affSColin Finck             DC_vUpdateLineBrush(dc);
79c2c66affSColin Finck 
80c2c66affSColin Finck         /* Special locking order to avoid lock-ups */
81c2c66affSColin Finck         pbrFill = dc->dclevel.pbrFill;
82c2c66affSColin Finck         pbrLine = dc->dclevel.pbrLine;
83c2c66affSColin Finck         psurf = dc->dclevel.pSurface;
84c2c66affSColin Finck         if (psurf == NULL)
85c2c66affSColin Finck         {
86c2c66affSColin Finck             /* Memory DC without a bitmap selected, nothing to do. */
87c2c66affSColin Finck             return TRUE;
88c2c66affSColin Finck         }
89c2c66affSColin Finck 
90c2c66affSColin Finck         /* Now fill the polygon with the current fill brush. */
91c2c66affSColin Finck         if (!(pbrFill->flAttrs & BR_IS_NULL))
92c2c66affSColin Finck         {
93c2c66affSColin Finck             BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
94c2c66affSColin Finck             BrushOrigin.x += dc->ptlDCOrig.x;
95c2c66affSColin Finck             BrushOrigin.y += dc->ptlDCOrig.y;
96c2c66affSColin Finck             ret = IntFillPolygon (dc,
97c2c66affSColin Finck                                   psurf,
98c2c66affSColin Finck                                   &dc->eboFill.BrushObject,
99c2c66affSColin Finck                                   Points,
100c2c66affSColin Finck                                   Count,
101c2c66affSColin Finck                                   DestRect,
102c2c66affSColin Finck                                   &BrushOrigin);
103c2c66affSColin Finck         }
104c2c66affSColin Finck 
105c2c66affSColin Finck         // Draw the Polygon Edges with the current pen ( if not a NULL pen )
106c2c66affSColin Finck         if (!(pbrLine->flAttrs & BR_IS_NULL))
107c2c66affSColin Finck         {
108c2c66affSColin Finck             int i;
109c2c66affSColin Finck 
110c2c66affSColin Finck             for (i = 0; i < Count-1; i++)
111c2c66affSColin Finck             {
112c2c66affSColin Finck 
113c2c66affSColin Finck // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
114c2c66affSColin Finck //                                 Points[0].x, Points[0].y,
115c2c66affSColin Finck //                                 Points[1].x, Points[1].y );
116c2c66affSColin Finck 
117c2c66affSColin Finck                 ret = IntEngLineTo(&psurf->SurfObj,
118c2c66affSColin Finck                                    (CLIPOBJ *)&dc->co,
119c2c66affSColin Finck                                    &dc->eboLine.BrushObject,
120c2c66affSColin Finck                                    Points[i].x,          /* From */
121c2c66affSColin Finck                                    Points[i].y,
122c2c66affSColin Finck                                    Points[i+1].x,        /* To */
123c2c66affSColin Finck                                    Points[i+1].y,
124c2c66affSColin Finck                                    &DestRect,
125c2c66affSColin Finck                                    ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
126c2c66affSColin Finck                 if (!ret) break;
127c2c66affSColin Finck             }
128c2c66affSColin Finck             /* Close the polygon */
129c2c66affSColin Finck             if (ret)
130c2c66affSColin Finck             {
131c2c66affSColin Finck                 ret = IntEngLineTo(&psurf->SurfObj,
132c2c66affSColin Finck                                    (CLIPOBJ *)&dc->co,
133c2c66affSColin Finck                                    &dc->eboLine.BrushObject,
134c2c66affSColin Finck                                    Points[Count-1].x, /* From */
135c2c66affSColin Finck                                    Points[Count-1].y,
136c2c66affSColin Finck                                    Points[0].x,       /* To */
137c2c66affSColin Finck                                    Points[0].y,
138c2c66affSColin Finck                                    &DestRect,
139c2c66affSColin Finck                                    ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
140c2c66affSColin Finck             }
141c2c66affSColin Finck         }
142c2c66affSColin Finck     }
143c2c66affSColin Finck 
144c2c66affSColin Finck     return ret;
145c2c66affSColin Finck }
146c2c66affSColin Finck 
147c2c66affSColin Finck BOOL FASTCALL
148c2c66affSColin Finck IntGdiPolyPolygon(DC      *dc,
149c2c66affSColin Finck                   LPPOINT Points,
150c2c66affSColin Finck                   PULONG  PolyCounts,
151c2c66affSColin Finck                   int     Count)
152c2c66affSColin Finck {
153c2c66affSColin Finck     if (PATH_IsPathOpen(dc->dclevel))
154c2c66affSColin Finck         return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
155c2c66affSColin Finck 
156c2c66affSColin Finck     while (--Count >=0)
157c2c66affSColin Finck     {
158c2c66affSColin Finck         if (!IntGdiPolygon ( dc, Points, *PolyCounts ))
159c2c66affSColin Finck             return FALSE;
160c2c66affSColin Finck         Points+=*PolyCounts++;
161c2c66affSColin Finck     }
162c2c66affSColin Finck     return TRUE;
163c2c66affSColin Finck }
164c2c66affSColin Finck 
165c2c66affSColin Finck BOOL FASTCALL
166c2c66affSColin Finck IntPolygon(HDC hdc, POINT *Point, int Count)
167c2c66affSColin Finck {
168c2c66affSColin Finck     BOOL bResult;
169c2c66affSColin Finck     PDC pdc;
170c2c66affSColin Finck 
171c2c66affSColin Finck     pdc = DC_LockDc(hdc);
172c2c66affSColin Finck     if (pdc == NULL)
173c2c66affSColin Finck     {
174c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
175c2c66affSColin Finck         return FALSE;
176c2c66affSColin Finck     }
177c2c66affSColin Finck 
178c2c66affSColin Finck     bResult = IntGdiPolygon(pdc, Point, Count);
179c2c66affSColin Finck 
180c2c66affSColin Finck     DC_UnlockDc(pdc);
181c2c66affSColin Finck     return bResult;
182c2c66affSColin Finck }
183c2c66affSColin Finck 
184c2c66affSColin Finck 
185c2c66affSColin Finck /******************************************************************************/
186c2c66affSColin Finck 
187c2c66affSColin Finck /*
188c2c66affSColin Finck  * NtGdiEllipse
189c2c66affSColin Finck  *
190c2c66affSColin Finck  * Author
191c2c66affSColin Finck  *    Filip Navara
192c2c66affSColin Finck  *
193c2c66affSColin Finck  * Remarks
194c2c66affSColin Finck  *    This function uses optimized Bresenham's ellipse algorithm. It draws
195c2c66affSColin Finck  *    four lines of the ellipse in one pass.
196c2c66affSColin Finck  *
197c2c66affSColin Finck  */
198c2c66affSColin Finck 
199c2c66affSColin Finck BOOL APIENTRY
200c2c66affSColin Finck NtGdiEllipse(
201c2c66affSColin Finck     HDC hDC,
202c2c66affSColin Finck     int Left,
203c2c66affSColin Finck     int Top,
204c2c66affSColin Finck     int Right,
205c2c66affSColin Finck     int Bottom)
206c2c66affSColin Finck {
207c2c66affSColin Finck     PDC dc;
208c2c66affSColin Finck     PDC_ATTR pdcattr;
209c2c66affSColin Finck     RECTL RectBounds;
210c2c66affSColin Finck     PBRUSH pbrush;
211c2c66affSColin Finck     BOOL ret = TRUE;
212c2c66affSColin Finck     LONG PenWidth, PenOrigWidth;
213c2c66affSColin Finck     LONG RadiusX, RadiusY, CenterX, CenterY;
214c2c66affSColin Finck     PBRUSH pFillBrushObj;
215c2c66affSColin Finck     BRUSH tmpFillBrushObj;
216c2c66affSColin Finck 
217c2c66affSColin Finck     dc = DC_LockDc(hDC);
218c2c66affSColin Finck     if (dc == NULL)
219c2c66affSColin Finck     {
220c2c66affSColin Finck        EngSetLastError(ERROR_INVALID_HANDLE);
221c2c66affSColin Finck        return FALSE;
222c2c66affSColin Finck     }
223c2c66affSColin Finck 
224c2c66affSColin Finck     if (PATH_IsPathOpen(dc->dclevel))
225c2c66affSColin Finck     {
226c2c66affSColin Finck         ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
227c2c66affSColin Finck         DC_UnlockDc(dc);
228c2c66affSColin Finck         return ret;
229c2c66affSColin Finck     }
230c2c66affSColin Finck 
231c2c66affSColin Finck     ////
232c2c66affSColin Finck     //// Could this use PATH_CheckCorners ?
233c2c66affSColin Finck     ////
234c2c66affSColin Finck     if ((Left == Right) || (Top == Bottom))
235c2c66affSColin Finck     {
236c2c66affSColin Finck        DC_UnlockDc(dc);
237c2c66affSColin Finck        return TRUE;
238c2c66affSColin Finck     }
239c2c66affSColin Finck 
240c2c66affSColin Finck     if (Right < Left)
241c2c66affSColin Finck     {
242c2c66affSColin Finck        INT tmp = Right; Right = Left; Left = tmp;
243c2c66affSColin Finck     }
244c2c66affSColin Finck     if (Bottom < Top)
245c2c66affSColin Finck     {
246c2c66affSColin Finck        INT tmp = Bottom; Bottom = Top; Top = tmp;
247c2c66affSColin Finck     }
248c2c66affSColin Finck     ////
249c2c66affSColin Finck 
250c2c66affSColin Finck     pdcattr = dc->pdcattr;
251c2c66affSColin Finck 
252c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
253c2c66affSColin Finck         DC_vUpdateFillBrush(dc);
254c2c66affSColin Finck 
255c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
256c2c66affSColin Finck         DC_vUpdateLineBrush(dc);
257c2c66affSColin Finck 
258c2c66affSColin Finck     pbrush = PEN_ShareLockPen(pdcattr->hpen);
259c2c66affSColin Finck     if (!pbrush)
260c2c66affSColin Finck     {
261c2c66affSColin Finck         DPRINT1("Ellipse Fail 1\n");
262c2c66affSColin Finck         DC_UnlockDc(dc);
263c2c66affSColin Finck         EngSetLastError(ERROR_INTERNAL_ERROR);
264c2c66affSColin Finck         return FALSE;
265c2c66affSColin Finck     }
266c2c66affSColin Finck 
267c2c66affSColin Finck     PenOrigWidth = PenWidth = pbrush->lWidth;
268c2c66affSColin Finck     if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0;
269c2c66affSColin Finck 
270c2c66affSColin Finck     if (pbrush->ulPenStyle == PS_INSIDEFRAME)
271c2c66affSColin Finck     {
272c2c66affSColin Finck        if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
273c2c66affSColin Finck        if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
274c2c66affSColin Finck        Left   += PenWidth / 2;
275c2c66affSColin Finck        Right  -= (PenWidth - 1) / 2;
276c2c66affSColin Finck        Top    += PenWidth / 2;
277c2c66affSColin Finck        Bottom -= (PenWidth - 1) / 2;
278c2c66affSColin Finck     }
279c2c66affSColin Finck 
280c2c66affSColin Finck     if (!PenWidth) PenWidth = 1;
281c2c66affSColin Finck     pbrush->lWidth = PenWidth;
282c2c66affSColin Finck 
283c2c66affSColin Finck     RectBounds.left   = Left;
284c2c66affSColin Finck     RectBounds.right  = Right;
285c2c66affSColin Finck     RectBounds.top    = Top;
286c2c66affSColin Finck     RectBounds.bottom = Bottom;
287c2c66affSColin Finck 
288c2c66affSColin Finck     IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
289c2c66affSColin Finck 
290c2c66affSColin Finck     RectBounds.left += dc->ptlDCOrig.x;
291c2c66affSColin Finck     RectBounds.right += dc->ptlDCOrig.x;
292c2c66affSColin Finck     RectBounds.top += dc->ptlDCOrig.y;
293c2c66affSColin Finck     RectBounds.bottom += dc->ptlDCOrig.y;
294c2c66affSColin Finck 
295c2c66affSColin Finck     // Setup for dynamic width and height.
296c2c66affSColin Finck     RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
297c2c66affSColin Finck     RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
298c2c66affSColin Finck     CenterX = (RectBounds.right + RectBounds.left) / 2;
299c2c66affSColin Finck     CenterY = (RectBounds.bottom + RectBounds.top) / 2;
300c2c66affSColin Finck 
301c2c66affSColin Finck     DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
302c2c66affSColin Finck                RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
303c2c66affSColin Finck 
304c2c66affSColin Finck     DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
305c2c66affSColin Finck                CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
306c2c66affSColin Finck 
307c2c66affSColin Finck     pFillBrushObj = BRUSH_ShareLockBrush(pdcattr->hbrush);
308c2c66affSColin Finck     if (NULL == pFillBrushObj)
309c2c66affSColin Finck     {
310c2c66affSColin Finck         DPRINT1("FillEllipse Fail\n");
311c2c66affSColin Finck         EngSetLastError(ERROR_INTERNAL_ERROR);
312c2c66affSColin Finck         ret = FALSE;
313c2c66affSColin Finck     }
314c2c66affSColin Finck     else
315c2c66affSColin Finck     {
316c2c66affSColin Finck         RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj));
317c2c66affSColin Finck         //tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
318c2c66affSColin Finck         //tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
319c2c66affSColin Finck         tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x;
320c2c66affSColin Finck         tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y;
321c2c66affSColin Finck 
322c2c66affSColin Finck         DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL);
323c2c66affSColin Finck 
324c2c66affSColin Finck         ret = IntFillEllipse( dc,
325c2c66affSColin Finck                               CenterX - RadiusX,
326c2c66affSColin Finck                               CenterY - RadiusY,
327c2c66affSColin Finck                               RadiusX*2, // Width
328c2c66affSColin Finck                               RadiusY*2, // Height
329c2c66affSColin Finck                               &tmpFillBrushObj);
330c2c66affSColin Finck         BRUSH_ShareUnlockBrush(pFillBrushObj);
331c2c66affSColin Finck 
332c2c66affSColin Finck         if (ret)
333c2c66affSColin Finck         {
334c2c66affSColin Finck            ret = IntDrawEllipse( dc,
335c2c66affSColin Finck                                  CenterX - RadiusX,
336c2c66affSColin Finck                                  CenterY - RadiusY,
337c2c66affSColin Finck                                  RadiusX*2, // Width
338c2c66affSColin Finck                                  RadiusY*2, // Height
339c2c66affSColin Finck                                  pbrush);
340c2c66affSColin Finck         }
341c2c66affSColin Finck 
342c2c66affSColin Finck         DC_vFinishBlit(dc, NULL);
343c2c66affSColin Finck     }
344c2c66affSColin Finck 
345c2c66affSColin Finck     pbrush->lWidth = PenOrigWidth;
346c2c66affSColin Finck     PEN_ShareUnlockPen(pbrush);
347c2c66affSColin Finck     DC_UnlockDc(dc);
348c2c66affSColin Finck     DPRINT("Ellipse Exit.\n");
349c2c66affSColin Finck     return ret;
350c2c66affSColin Finck }
351c2c66affSColin Finck 
352c2c66affSColin Finck #if 0
353c2c66affSColin Finck 
354c2c66affSColin Finck // When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
355c2c66affSColin Finck // even-numbered polygon sides on each scan line. That is, GDI fills the area between the
356c2c66affSColin Finck // first and second side, between the third and fourth side, and so on.
357c2c66affSColin Finck 
358c2c66affSColin Finck // WINDING Selects winding mode (fills any region with a nonzero winding value).
359c2c66affSColin Finck // When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
360c2c66affSColin Finck // This value is defined as the number of times a pen used to draw the polygon would go around the region.
361c2c66affSColin Finck // The direction of each edge of the polygon is important.
362c2c66affSColin Finck 
363c2c66affSColin Finck extern BOOL FillPolygon(PDC dc,
364c2c66affSColin Finck                             SURFOBJ *SurfObj,
365c2c66affSColin Finck                             PBRUSHOBJ BrushObj,
366c2c66affSColin Finck                             MIX RopMode,
367c2c66affSColin Finck                             CONST PPOINT Points,
368c2c66affSColin Finck                             int Count,
369c2c66affSColin Finck                             RECTL BoundRect);
370c2c66affSColin Finck 
371c2c66affSColin Finck #endif
372c2c66affSColin Finck 
373c2c66affSColin Finck 
374c2c66affSColin Finck ULONG_PTR
375c2c66affSColin Finck APIENTRY
376c2c66affSColin Finck NtGdiPolyPolyDraw( IN HDC hDC,
377c2c66affSColin Finck                    IN PPOINT UnsafePoints,
378c2c66affSColin Finck                    IN PULONG UnsafeCounts,
379c2c66affSColin Finck                    IN ULONG Count,
380c2c66affSColin Finck                    IN INT iFunc )
381c2c66affSColin Finck {
382c2c66affSColin Finck     DC *dc;
383c2c66affSColin Finck     PVOID pTemp;
384c2c66affSColin Finck     LPPOINT SafePoints;
385c2c66affSColin Finck     PULONG SafeCounts;
386c2c66affSColin Finck     NTSTATUS Status = STATUS_SUCCESS;
387c2c66affSColin Finck     BOOL Ret = TRUE;
388c2c66affSColin Finck     ULONG nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
389c2c66affSColin Finck 
390c2c66affSColin Finck     if (!UnsafePoints || !UnsafeCounts ||
391c2c66affSColin Finck         Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
392c2c66affSColin Finck     {
393c2c66affSColin Finck         /* Windows doesn't set last error */
394c2c66affSColin Finck         return FALSE;
395c2c66affSColin Finck     }
396c2c66affSColin Finck 
397c2c66affSColin Finck     _SEH2_TRY
398c2c66affSColin Finck     {
399c2c66affSColin Finck         ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
400c2c66affSColin Finck         ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
401c2c66affSColin Finck 
402c2c66affSColin Finck         /* Count points and validate poligons */
403c2c66affSColin Finck         for (i = 0; i < Count; i++)
404c2c66affSColin Finck         {
405c2c66affSColin Finck             if (UnsafeCounts[i] < 2)
406c2c66affSColin Finck             {
407c2c66affSColin Finck                 nInvalid++;
408c2c66affSColin Finck             }
409c2c66affSColin Finck             nPoints += UnsafeCounts[i];
410c2c66affSColin Finck             nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
411c2c66affSColin Finck         }
412c2c66affSColin Finck     }
413c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
414c2c66affSColin Finck     {
415c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
416c2c66affSColin Finck     }
417c2c66affSColin Finck     _SEH2_END;
418c2c66affSColin Finck 
419c2c66affSColin Finck     if (!NT_SUCCESS(Status))
420c2c66affSColin Finck     {
421c2c66affSColin Finck         /* Windows doesn't set last error */
422c2c66affSColin Finck         return FALSE;
423c2c66affSColin Finck     }
424c2c66affSColin Finck 
425c2c66affSColin Finck     if (nPoints == 0 || nPoints < nMaxPoints)
426c2c66affSColin Finck     {
427c2c66affSColin Finck         /* If all polygon counts are zero, or we have overflow,
428c2c66affSColin Finck            return without setting a last error code. */
429c2c66affSColin Finck         return FALSE;
430c2c66affSColin Finck     }
431c2c66affSColin Finck 
432c2c66affSColin Finck     if (nInvalid != 0)
433c2c66affSColin Finck     {
434c2c66affSColin Finck         /* If at least one poly count is 0 or 1, fail */
435c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_PARAMETER);
436c2c66affSColin Finck         return FALSE;
437c2c66affSColin Finck     }
438c2c66affSColin Finck 
439c2c66affSColin Finck     /* Allocate one buffer for both counts and points */
440c2c66affSColin Finck     pTemp = ExAllocatePoolWithTag(PagedPool,
441c2c66affSColin Finck                                   Count * sizeof(ULONG) + nPoints * sizeof(POINT),
442c2c66affSColin Finck                                   TAG_SHAPE);
443c2c66affSColin Finck     if (!pTemp)
444c2c66affSColin Finck     {
445c2c66affSColin Finck         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
446c2c66affSColin Finck         return FALSE;
447c2c66affSColin Finck     }
448c2c66affSColin Finck 
449c2c66affSColin Finck     SafeCounts = pTemp;
450c2c66affSColin Finck     SafePoints = (PVOID)(SafeCounts + Count);
451c2c66affSColin Finck 
452c2c66affSColin Finck     _SEH2_TRY
453c2c66affSColin Finck     {
454c2c66affSColin Finck         /* Pointers already probed! */
455c2c66affSColin Finck         RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
456c2c66affSColin Finck         RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
457c2c66affSColin Finck     }
458c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
459c2c66affSColin Finck     {
460c2c66affSColin Finck         Status = _SEH2_GetExceptionCode();
461c2c66affSColin Finck     }
462c2c66affSColin Finck     _SEH2_END;
463c2c66affSColin Finck 
464c2c66affSColin Finck     if (!NT_SUCCESS(Status))
465c2c66affSColin Finck     {
466c2c66affSColin Finck         ExFreePoolWithTag(pTemp, TAG_SHAPE);
467c2c66affSColin Finck         return FALSE;
468c2c66affSColin Finck     }
469c2c66affSColin Finck 
470c2c66affSColin Finck     /* Special handling for GdiPolyPolyRgn */
471c2c66affSColin Finck     if (iFunc == GdiPolyPolyRgn)
472c2c66affSColin Finck     {
473c2c66affSColin Finck         INT iMode = (INT)(UINT_PTR)hDC;
474c2c66affSColin Finck         HRGN hrgn;
475c2c66affSColin Finck 
476c2c66affSColin Finck         hrgn = GreCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, iMode);
477c2c66affSColin Finck 
478c2c66affSColin Finck         ExFreePoolWithTag(pTemp, TAG_SHAPE);
479c2c66affSColin Finck         return (ULONG_PTR)hrgn;
480c2c66affSColin Finck     }
481c2c66affSColin Finck 
482c2c66affSColin Finck     dc = DC_LockDc(hDC);
483c2c66affSColin Finck     if (!dc)
484c2c66affSColin Finck     {
485c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
486c2c66affSColin Finck         ExFreePoolWithTag(pTemp, TAG_SHAPE);
487c2c66affSColin Finck         return FALSE;
488c2c66affSColin Finck     }
489c2c66affSColin Finck 
490c2c66affSColin Finck     DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
491c2c66affSColin Finck 
492c2c66affSColin Finck     if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
493c2c66affSColin Finck         DC_vUpdateFillBrush(dc);
494c2c66affSColin Finck 
495c2c66affSColin Finck     if (dc->pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
496c2c66affSColin Finck         DC_vUpdateLineBrush(dc);
497c2c66affSColin Finck 
498c2c66affSColin Finck     /* Perform the actual work */
499c2c66affSColin Finck     switch (iFunc)
500c2c66affSColin Finck     {
501c2c66affSColin Finck         case GdiPolyPolygon:
502c2c66affSColin Finck             Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
503c2c66affSColin Finck             break;
504c2c66affSColin Finck         case GdiPolyPolyLine:
505c2c66affSColin Finck             Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
506c2c66affSColin Finck             break;
507c2c66affSColin Finck         case GdiPolyBezier:
508c2c66affSColin Finck             Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
509c2c66affSColin Finck             break;
510c2c66affSColin Finck         case GdiPolyLineTo:
511c2c66affSColin Finck             Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
512c2c66affSColin Finck             break;
513c2c66affSColin Finck         case GdiPolyBezierTo:
514c2c66affSColin Finck             Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
515c2c66affSColin Finck             break;
516c2c66affSColin Finck         default:
517c2c66affSColin Finck             EngSetLastError(ERROR_INVALID_PARAMETER);
518c2c66affSColin Finck             Ret = FALSE;
519c2c66affSColin Finck     }
520c2c66affSColin Finck 
521c2c66affSColin Finck     /* Cleanup and return */
522c2c66affSColin Finck     DC_vFinishBlit(dc, NULL);
523c2c66affSColin Finck     DC_UnlockDc(dc);
524c2c66affSColin Finck     ExFreePoolWithTag(pTemp, TAG_SHAPE);
525c2c66affSColin Finck 
526c2c66affSColin Finck     return (ULONG_PTR)Ret;
527c2c66affSColin Finck }
528c2c66affSColin Finck 
529c2c66affSColin Finck 
530c2c66affSColin Finck BOOL
531c2c66affSColin Finck FASTCALL
532c2c66affSColin Finck IntRectangle(PDC dc,
533c2c66affSColin Finck              int LeftRect,
534c2c66affSColin Finck              int TopRect,
535c2c66affSColin Finck              int RightRect,
536c2c66affSColin Finck              int BottomRect)
537c2c66affSColin Finck {
538c2c66affSColin Finck     SURFACE *psurf = NULL;
539c2c66affSColin Finck     PBRUSH pbrLine, pbrFill;
540c2c66affSColin Finck     BOOL       ret = FALSE; // Default to failure
541c2c66affSColin Finck     RECTL      DestRect;
542c2c66affSColin Finck     MIX        Mix;
543c2c66affSColin Finck     PDC_ATTR pdcattr;
544c2c66affSColin Finck     POINTL BrushOrigin;
545c2c66affSColin Finck 
546c2c66affSColin Finck     ASSERT ( dc ); // Caller's responsibility to set this up
547c2c66affSColin Finck 
548c2c66affSColin Finck     pdcattr = dc->pdcattr;
549c2c66affSColin Finck 
550c2c66affSColin Finck     // Rectangle Path only.
551c2c66affSColin Finck     if ( PATH_IsPathOpen(dc->dclevel) )
552c2c66affSColin Finck     {
553c2c66affSColin Finck         return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
554c2c66affSColin Finck     }
555c2c66affSColin Finck 
556c2c66affSColin Finck 	/* Make sure rectangle is not inverted */
557c2c66affSColin Finck     DestRect.left   = min(LeftRect, RightRect);
558c2c66affSColin Finck     DestRect.right  = max(LeftRect, RightRect);
559c2c66affSColin Finck     DestRect.top    = min(TopRect,  BottomRect);
560c2c66affSColin Finck     DestRect.bottom = max(TopRect,  BottomRect);
561c2c66affSColin Finck 
562c2c66affSColin Finck     IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
563c2c66affSColin Finck 
564c2c66affSColin Finck     DestRect.left   += dc->ptlDCOrig.x;
565c2c66affSColin Finck     DestRect.right  += dc->ptlDCOrig.x;
566c2c66affSColin Finck     DestRect.top    += dc->ptlDCOrig.y;
567c2c66affSColin Finck     DestRect.bottom += dc->ptlDCOrig.y;
568c2c66affSColin Finck 
569c2c66affSColin Finck     if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
570c2c66affSColin Finck     {
571c2c66affSColin Finck        IntUpdateBoundsRect(dc, &DestRect);
572c2c66affSColin Finck     }
573c2c66affSColin Finck 
574c2c66affSColin Finck     /* In GM_COMPATIBLE, don't include bottom and right edges */
575c2c66affSColin Finck     if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
576c2c66affSColin Finck     {
577c2c66affSColin Finck         DestRect.right--;
578c2c66affSColin Finck         DestRect.bottom--;
579c2c66affSColin Finck     }
580c2c66affSColin Finck 
581c2c66affSColin Finck     DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
582c2c66affSColin Finck 
583c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
584c2c66affSColin Finck         DC_vUpdateFillBrush(dc);
585c2c66affSColin Finck 
586c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
587c2c66affSColin Finck         DC_vUpdateLineBrush(dc);
588c2c66affSColin Finck 
589c2c66affSColin Finck     pbrFill = dc->dclevel.pbrFill;
590c2c66affSColin Finck     pbrLine = dc->dclevel.pbrLine;
591c2c66affSColin Finck     if (!pbrLine)
592c2c66affSColin Finck     {
593c2c66affSColin Finck         ret = FALSE;
594c2c66affSColin Finck         goto cleanup;
595c2c66affSColin Finck     }
596c2c66affSColin Finck 
597c2c66affSColin Finck     psurf = dc->dclevel.pSurface;
598c2c66affSColin Finck     if (!psurf)
599c2c66affSColin Finck     {
600c2c66affSColin Finck         ret = TRUE;
601c2c66affSColin Finck         goto cleanup;
602c2c66affSColin Finck     }
603c2c66affSColin Finck 
604c2c66affSColin Finck     if (pbrFill)
605c2c66affSColin Finck     {
606c2c66affSColin Finck         if (!(pbrFill->flAttrs & BR_IS_NULL))
607c2c66affSColin Finck         {
608c2c66affSColin Finck             BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
609c2c66affSColin Finck             BrushOrigin.x += dc->ptlDCOrig.x;
610c2c66affSColin Finck             BrushOrigin.y += dc->ptlDCOrig.y;
611c2c66affSColin Finck             ret = IntEngBitBlt(&psurf->SurfObj,
612c2c66affSColin Finck                                NULL,
613c2c66affSColin Finck                                NULL,
614c2c66affSColin Finck                                (CLIPOBJ *)&dc->co,
615c2c66affSColin Finck                                NULL,
616c2c66affSColin Finck                                &DestRect,
617c2c66affSColin Finck                                NULL,
618c2c66affSColin Finck                                NULL,
619c2c66affSColin Finck                                &dc->eboFill.BrushObject,
620c2c66affSColin Finck                                &BrushOrigin,
621c2c66affSColin Finck                                ROP4_FROM_INDEX(R3_OPINDEX_PATCOPY));
622c2c66affSColin Finck         }
623c2c66affSColin Finck     }
624c2c66affSColin Finck 
625c2c66affSColin Finck     // Draw the rectangle with the current pen
626c2c66affSColin Finck 
627c2c66affSColin Finck     ret = TRUE; // Change default to success
628c2c66affSColin Finck 
629c2c66affSColin Finck     if (!(pbrLine->flAttrs & BR_IS_NULL))
630c2c66affSColin Finck     {
631c2c66affSColin Finck         Mix = ROP2_TO_MIX(pdcattr->jROP2);
632c2c66affSColin Finck         ret = ret && IntEngLineTo(&psurf->SurfObj,
633c2c66affSColin Finck                                   (CLIPOBJ *)&dc->co,
634c2c66affSColin Finck                                   &dc->eboLine.BrushObject,
635c2c66affSColin Finck                                   DestRect.left, DestRect.top, DestRect.right, DestRect.top,
636c2c66affSColin Finck                                   &DestRect, // Bounding rectangle
637c2c66affSColin Finck                                   Mix);
638c2c66affSColin Finck 
639c2c66affSColin Finck         ret = ret && IntEngLineTo(&psurf->SurfObj,
640c2c66affSColin Finck                                   (CLIPOBJ *)&dc->co,
641c2c66affSColin Finck                                   &dc->eboLine.BrushObject,
642c2c66affSColin Finck                                   DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
643c2c66affSColin Finck                                   &DestRect, // Bounding rectangle
644c2c66affSColin Finck                                   Mix);
645c2c66affSColin Finck 
646c2c66affSColin Finck         ret = ret && IntEngLineTo(&psurf->SurfObj,
647c2c66affSColin Finck                                   (CLIPOBJ *)&dc->co,
648c2c66affSColin Finck                                   &dc->eboLine.BrushObject,
649c2c66affSColin Finck                                   DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
650c2c66affSColin Finck                                   &DestRect, // Bounding rectangle
651c2c66affSColin Finck                                   Mix);
652c2c66affSColin Finck 
653c2c66affSColin Finck         ret = ret && IntEngLineTo(&psurf->SurfObj,
654c2c66affSColin Finck                                   (CLIPOBJ *)&dc->co,
655c2c66affSColin Finck                                   &dc->eboLine.BrushObject,
656c2c66affSColin Finck                                   DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
657c2c66affSColin Finck                                   &DestRect, // Bounding rectangle
658c2c66affSColin Finck                                   Mix);
659c2c66affSColin Finck     }
660c2c66affSColin Finck 
661c2c66affSColin Finck cleanup:
662c2c66affSColin Finck     DC_vFinishBlit(dc, NULL);
663c2c66affSColin Finck 
664c2c66affSColin Finck     /* Move current position in DC?
665c2c66affSColin Finck        MSDN: The current position is neither used nor updated by Rectangle. */
666c2c66affSColin Finck 
667c2c66affSColin Finck     return ret;
668c2c66affSColin Finck }
669c2c66affSColin Finck 
670c2c66affSColin Finck BOOL
671c2c66affSColin Finck APIENTRY
672c2c66affSColin Finck NtGdiRectangle(HDC  hDC,
673c2c66affSColin Finck                int  LeftRect,
674c2c66affSColin Finck                int  TopRect,
675c2c66affSColin Finck                int  RightRect,
676c2c66affSColin Finck                int  BottomRect)
677c2c66affSColin Finck {
678c2c66affSColin Finck     DC   *dc;
679c2c66affSColin Finck     BOOL ret; // Default to failure
680c2c66affSColin Finck 
681c2c66affSColin Finck     dc = DC_LockDc(hDC);
682c2c66affSColin Finck     if (!dc)
683c2c66affSColin Finck     {
684c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
685c2c66affSColin Finck         return FALSE;
686c2c66affSColin Finck     }
687c2c66affSColin Finck 
688c2c66affSColin Finck     /* Do we rotate or shear? */
689c2c66affSColin Finck     if (!(dc->pdcattr->mxWorldToDevice.flAccel & XFORM_SCALE))
690c2c66affSColin Finck     {
691c2c66affSColin Finck         POINTL DestCoords[4];
692c2c66affSColin Finck         ULONG PolyCounts = 4;
693c2c66affSColin Finck 
694c2c66affSColin Finck         DestCoords[0].x = DestCoords[3].x = LeftRect;
695c2c66affSColin Finck         DestCoords[0].y = DestCoords[1].y = TopRect;
696c2c66affSColin Finck         DestCoords[1].x = DestCoords[2].x = RightRect;
697c2c66affSColin Finck         DestCoords[2].y = DestCoords[3].y = BottomRect;
698c2c66affSColin Finck         // Use IntGdiPolyPolygon so to support PATH.
699c2c66affSColin Finck         ret = IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
700c2c66affSColin Finck     }
701c2c66affSColin Finck     else
702c2c66affSColin Finck     {
703c2c66affSColin Finck         ret = IntRectangle(dc, LeftRect, TopRect, RightRect, BottomRect );
704c2c66affSColin Finck     }
705c2c66affSColin Finck 
706c2c66affSColin Finck     DC_UnlockDc(dc);
707c2c66affSColin Finck 
708c2c66affSColin Finck     return ret;
709c2c66affSColin Finck }
710c2c66affSColin Finck 
711c2c66affSColin Finck 
712c2c66affSColin Finck BOOL
713c2c66affSColin Finck FASTCALL
714c2c66affSColin Finck IntRoundRect(
715c2c66affSColin Finck     PDC  dc,
716c2c66affSColin Finck     int  Left,
717c2c66affSColin Finck     int  Top,
718c2c66affSColin Finck     int  Right,
719c2c66affSColin Finck     int  Bottom,
720c2c66affSColin Finck     int  xCurveDiameter,
721c2c66affSColin Finck     int  yCurveDiameter)
722c2c66affSColin Finck {
723c2c66affSColin Finck     PDC_ATTR pdcattr;
724c2c66affSColin Finck     PBRUSH   pbrLine, pbrFill;
725c2c66affSColin Finck     RECTL RectBounds;
726c2c66affSColin Finck     LONG PenWidth, PenOrigWidth;
727c2c66affSColin Finck     BOOL ret = TRUE; // Default to success
728c2c66affSColin Finck     BRUSH brushTemp;
729c2c66affSColin Finck 
730c2c66affSColin Finck     ASSERT ( dc ); // Caller's responsibility to set this up
731c2c66affSColin Finck 
732c2c66affSColin Finck     if ( PATH_IsPathOpen(dc->dclevel) )
733c2c66affSColin Finck         return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
734c2c66affSColin Finck                                 xCurveDiameter, yCurveDiameter );
735c2c66affSColin Finck 
736c2c66affSColin Finck     if ((Left == Right) || (Top == Bottom)) return TRUE;
737c2c66affSColin Finck 
738c2c66affSColin Finck     xCurveDiameter = max(abs( xCurveDiameter ), 1);
739c2c66affSColin Finck     yCurveDiameter = max(abs( yCurveDiameter ), 1);
740c2c66affSColin Finck 
741c2c66affSColin Finck     if (Right < Left)
742c2c66affSColin Finck     {
743c2c66affSColin Finck        INT tmp = Right; Right = Left; Left = tmp;
744c2c66affSColin Finck     }
745c2c66affSColin Finck     if (Bottom < Top)
746c2c66affSColin Finck     {
747c2c66affSColin Finck        INT tmp = Bottom; Bottom = Top; Top = tmp;
748c2c66affSColin Finck     }
749c2c66affSColin Finck 
750c2c66affSColin Finck     pdcattr = dc->pdcattr;
751c2c66affSColin Finck 
752c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
753c2c66affSColin Finck         DC_vUpdateFillBrush(dc);
754c2c66affSColin Finck 
755c2c66affSColin Finck     if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
756c2c66affSColin Finck         DC_vUpdateLineBrush(dc);
757c2c66affSColin Finck 
758c2c66affSColin Finck     pbrLine = PEN_ShareLockPen(pdcattr->hpen);
759c2c66affSColin Finck     if (!pbrLine)
760c2c66affSColin Finck     {
761c2c66affSColin Finck         /* Nothing to do, as we don't have a bitmap */
762c2c66affSColin Finck         EngSetLastError(ERROR_INTERNAL_ERROR);
763c2c66affSColin Finck         return FALSE;
764c2c66affSColin Finck     }
765c2c66affSColin Finck 
766c2c66affSColin Finck     PenOrigWidth = PenWidth = pbrLine->lWidth;
767c2c66affSColin Finck     if (pbrLine->ulPenStyle == PS_NULL) PenWidth = 0;
768c2c66affSColin Finck 
769c2c66affSColin Finck     if (pbrLine->ulPenStyle == PS_INSIDEFRAME)
770c2c66affSColin Finck     {
771c2c66affSColin Finck        if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
772c2c66affSColin Finck        if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
773c2c66affSColin Finck        Left   += PenWidth / 2;
774c2c66affSColin Finck        Right  -= (PenWidth - 1) / 2;
775c2c66affSColin Finck        Top    += PenWidth / 2;
776c2c66affSColin Finck        Bottom -= (PenWidth - 1) / 2;
777c2c66affSColin Finck     }
778c2c66affSColin Finck 
779c2c66affSColin Finck     if (!PenWidth) PenWidth = 1;
780c2c66affSColin Finck     pbrLine->lWidth = PenWidth;
781c2c66affSColin Finck 
782c2c66affSColin Finck     RectBounds.left = Left;
783c2c66affSColin Finck     RectBounds.top = Top;
784c2c66affSColin Finck     RectBounds.right = Right;
785c2c66affSColin Finck     RectBounds.bottom = Bottom;
786c2c66affSColin Finck 
787c2c66affSColin Finck     IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
788c2c66affSColin Finck 
789c2c66affSColin Finck     RectBounds.left   += dc->ptlDCOrig.x;
790c2c66affSColin Finck     RectBounds.top    += dc->ptlDCOrig.y;
791c2c66affSColin Finck     RectBounds.right  += dc->ptlDCOrig.x;
792c2c66affSColin Finck     RectBounds.bottom += dc->ptlDCOrig.y;
793c2c66affSColin Finck 
794c2c66affSColin Finck     pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
795c2c66affSColin Finck     if (!pbrFill)
796c2c66affSColin Finck     {
797c2c66affSColin Finck         DPRINT1("FillRound Fail\n");
798c2c66affSColin Finck         EngSetLastError(ERROR_INTERNAL_ERROR);
799c2c66affSColin Finck         ret = FALSE;
800c2c66affSColin Finck     }
801c2c66affSColin Finck     else
802c2c66affSColin Finck     {
803c2c66affSColin Finck 
804c2c66affSColin Finck         DC_vPrepareDCsForBlit(dc, &RectBounds, NULL, NULL);
805c2c66affSColin Finck 
806c2c66affSColin Finck         RtlCopyMemory(&brushTemp, pbrFill, sizeof(brushTemp));
807c2c66affSColin Finck         brushTemp.ptOrigin.x += RectBounds.left - Left;
808c2c66affSColin Finck         brushTemp.ptOrigin.y += RectBounds.top - Top;
809c2c66affSColin Finck         ret = IntFillRoundRect( dc,
810c2c66affSColin Finck                                 RectBounds.left,
811c2c66affSColin Finck                                 RectBounds.top,
812c2c66affSColin Finck                                 RectBounds.right,
813c2c66affSColin Finck                                 RectBounds.bottom,
814c2c66affSColin Finck                                 xCurveDiameter,
815c2c66affSColin Finck                                 yCurveDiameter,
816c2c66affSColin Finck                                 &brushTemp);
817c2c66affSColin Finck         BRUSH_ShareUnlockBrush(pbrFill);
818c2c66affSColin Finck 
819c2c66affSColin Finck         if (ret)
820c2c66affSColin Finck         {
821c2c66affSColin Finck            ret = IntDrawRoundRect( dc,
822c2c66affSColin Finck                       RectBounds.left,
823c2c66affSColin Finck                        RectBounds.top,
824c2c66affSColin Finck                      RectBounds.right,
825c2c66affSColin Finck                     RectBounds.bottom,
826c2c66affSColin Finck                        xCurveDiameter,
827c2c66affSColin Finck                        yCurveDiameter,
828c2c66affSColin Finck                        pbrLine);
829c2c66affSColin Finck         }
830c2c66affSColin Finck 
831c2c66affSColin Finck         DC_vFinishBlit(dc, NULL);
832c2c66affSColin Finck     }
833c2c66affSColin Finck 
834c2c66affSColin Finck 
835c2c66affSColin Finck     pbrLine->lWidth = PenOrigWidth;
836c2c66affSColin Finck     PEN_ShareUnlockPen(pbrLine);
837c2c66affSColin Finck     return ret;
838c2c66affSColin Finck }
839c2c66affSColin Finck 
840c2c66affSColin Finck BOOL
841c2c66affSColin Finck APIENTRY
842c2c66affSColin Finck NtGdiRoundRect(
843c2c66affSColin Finck     HDC  hDC,
844c2c66affSColin Finck     int  LeftRect,
845c2c66affSColin Finck     int  TopRect,
846c2c66affSColin Finck     int  RightRect,
847c2c66affSColin Finck     int  BottomRect,
848c2c66affSColin Finck     int  Width,
849c2c66affSColin Finck     int  Height)
850c2c66affSColin Finck {
851c2c66affSColin Finck     DC   *dc = DC_LockDc(hDC);
852c2c66affSColin Finck     BOOL  ret = FALSE; /* Default to failure */
853c2c66affSColin Finck 
854c2c66affSColin Finck     DPRINT("NtGdiRoundRect(0x%p,%i,%i,%i,%i,%i,%i)\n",hDC,LeftRect,TopRect,RightRect,BottomRect,Width,Height);
855c2c66affSColin Finck     if ( !dc )
856c2c66affSColin Finck     {
857c2c66affSColin Finck         DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
858c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
859c2c66affSColin Finck     }
860c2c66affSColin Finck     else
861c2c66affSColin Finck     {
862c2c66affSColin Finck         ret = IntRoundRect ( dc, LeftRect, TopRect, RightRect, BottomRect, Width, Height );
863c2c66affSColin Finck         DC_UnlockDc ( dc );
864c2c66affSColin Finck     }
865c2c66affSColin Finck 
866c2c66affSColin Finck     return ret;
867c2c66affSColin Finck }
868c2c66affSColin Finck 
869c2c66affSColin Finck BOOL
870c2c66affSColin Finck NTAPI
871c2c66affSColin Finck GreGradientFill(
872c2c66affSColin Finck     HDC hdc,
873c2c66affSColin Finck     PTRIVERTEX pVertex,
874c2c66affSColin Finck     ULONG nVertex,
875c2c66affSColin Finck     PVOID pMesh,
876c2c66affSColin Finck     ULONG nMesh,
877c2c66affSColin Finck     ULONG ulMode)
878c2c66affSColin Finck {
879c2c66affSColin Finck     PDC pdc;
880c2c66affSColin Finck     SURFACE *psurf;
881c2c66affSColin Finck     EXLATEOBJ exlo;
882c2c66affSColin Finck     RECTL rclExtent;
883c2c66affSColin Finck     POINTL ptlDitherOrg;
884c2c66affSColin Finck     ULONG i;
885c2c66affSColin Finck     BOOL bRet;
886c2c66affSColin Finck 
887c2c66affSColin Finck     /* Check parameters */
888c2c66affSColin Finck     if (ulMode & GRADIENT_FILL_TRIANGLE)
889c2c66affSColin Finck     {
890c2c66affSColin Finck         PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh;
891c2c66affSColin Finck 
892c2c66affSColin Finck         for (i = 0; i < nMesh; i++, pTriangle++)
893c2c66affSColin Finck         {
894c2c66affSColin Finck             if (pTriangle->Vertex1 >= nVertex ||
895c2c66affSColin Finck                 pTriangle->Vertex2 >= nVertex ||
896c2c66affSColin Finck                 pTriangle->Vertex3 >= nVertex)
897c2c66affSColin Finck             {
898c2c66affSColin Finck                 EngSetLastError(ERROR_INVALID_PARAMETER);
899c2c66affSColin Finck                 return FALSE;
900c2c66affSColin Finck             }
901c2c66affSColin Finck         }
902c2c66affSColin Finck     }
903c2c66affSColin Finck     else
904c2c66affSColin Finck     {
905c2c66affSColin Finck         PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh;
906c2c66affSColin Finck         for (i = 0; i < nMesh; i++, pRect++)
907c2c66affSColin Finck         {
908c2c66affSColin Finck             if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex)
909c2c66affSColin Finck             {
910c2c66affSColin Finck                 EngSetLastError(ERROR_INVALID_PARAMETER);
911c2c66affSColin Finck                 return FALSE;
912c2c66affSColin Finck             }
913c2c66affSColin Finck         }
914c2c66affSColin Finck     }
915c2c66affSColin Finck 
916c2c66affSColin Finck     /* Lock the output DC */
917c2c66affSColin Finck     pdc = DC_LockDc(hdc);
918c2c66affSColin Finck     if(!pdc)
919c2c66affSColin Finck     {
920c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
921c2c66affSColin Finck         return FALSE;
922c2c66affSColin Finck     }
923c2c66affSColin Finck 
924c2c66affSColin Finck     if (!pdc->dclevel.pSurface)
925c2c66affSColin Finck     {
926c2c66affSColin Finck         /* Memory DC with no surface selected */
927c2c66affSColin Finck         DC_UnlockDc(pdc);
928c2c66affSColin Finck         return TRUE; // CHECKME
929c2c66affSColin Finck     }
930c2c66affSColin Finck 
931c2c66affSColin Finck     /* Calculate extent */
932c2c66affSColin Finck     rclExtent.left = rclExtent.right = pVertex->x;
933c2c66affSColin Finck     rclExtent.top = rclExtent.bottom = pVertex->y;
934c2c66affSColin Finck     for (i = 0; i < nVertex; i++)
935c2c66affSColin Finck     {
936c2c66affSColin Finck         rclExtent.left = min(rclExtent.left, (pVertex + i)->x);
937c2c66affSColin Finck         rclExtent.right = max(rclExtent.right, (pVertex + i)->x);
938c2c66affSColin Finck         rclExtent.top = min(rclExtent.top, (pVertex + i)->y);
939c2c66affSColin Finck         rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y);
940c2c66affSColin Finck     }
941c2c66affSColin Finck     IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2);
942c2c66affSColin Finck 
943c2c66affSColin Finck     rclExtent.left   += pdc->ptlDCOrig.x;
944c2c66affSColin Finck     rclExtent.right  += pdc->ptlDCOrig.x;
945c2c66affSColin Finck     rclExtent.top    += pdc->ptlDCOrig.y;
946c2c66affSColin Finck     rclExtent.bottom += pdc->ptlDCOrig.y;
947c2c66affSColin Finck 
948456e2192STimo Kreuzer     if (RECTL_bIsEmptyRect(&rclExtent))
949456e2192STimo Kreuzer     {
950456e2192STimo Kreuzer         DC_UnlockDc(pdc);
951456e2192STimo Kreuzer         return TRUE;
952456e2192STimo Kreuzer     }
953456e2192STimo Kreuzer 
954c2c66affSColin Finck     ptlDitherOrg.x = ptlDitherOrg.y = 0;
955c2c66affSColin Finck     IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1);
956c2c66affSColin Finck 
957c2c66affSColin Finck     ptlDitherOrg.x += pdc->ptlDCOrig.x;
958c2c66affSColin Finck     ptlDitherOrg.y += pdc->ptlDCOrig.y;
959c2c66affSColin Finck 
960c2c66affSColin Finck    if (pdc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
961c2c66affSColin Finck    {
962c2c66affSColin Finck       IntUpdateBoundsRect(pdc, &rclExtent);
963c2c66affSColin Finck    }
964c2c66affSColin Finck 
965c2c66affSColin Finck     DC_vPrepareDCsForBlit(pdc, &rclExtent, NULL, NULL);
966c2c66affSColin Finck 
967c2c66affSColin Finck     psurf = pdc->dclevel.pSurface;
968c2c66affSColin Finck 
969c2c66affSColin Finck     EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0, 0);
970c2c66affSColin Finck 
971c2c66affSColin Finck     bRet = IntEngGradientFill(&psurf->SurfObj,
972c2c66affSColin Finck                              (CLIPOBJ *)&pdc->co,
973c2c66affSColin Finck                              &exlo.xlo,
974c2c66affSColin Finck                              pVertex,
975c2c66affSColin Finck                              nVertex,
976c2c66affSColin Finck                              pMesh,
977c2c66affSColin Finck                              nMesh,
978c2c66affSColin Finck                              &rclExtent,
979c2c66affSColin Finck                              &ptlDitherOrg,
980c2c66affSColin Finck                              ulMode);
981c2c66affSColin Finck 
982c2c66affSColin Finck     EXLATEOBJ_vCleanup(&exlo);
983c2c66affSColin Finck     DC_vFinishBlit(pdc, NULL);
984c2c66affSColin Finck     DC_UnlockDc(pdc);
985c2c66affSColin Finck 
986c2c66affSColin Finck     return bRet;
987c2c66affSColin Finck }
988c2c66affSColin Finck 
989c2c66affSColin Finck BOOL
990c2c66affSColin Finck APIENTRY
991c2c66affSColin Finck NtGdiGradientFill(
992c2c66affSColin Finck     HDC hdc,
993c2c66affSColin Finck     PTRIVERTEX pVertex,
994c2c66affSColin Finck     ULONG nVertex,
995c2c66affSColin Finck     PVOID pMesh,
996c2c66affSColin Finck     ULONG nMesh,
997c2c66affSColin Finck     ULONG ulMode)
998c2c66affSColin Finck {
999c2c66affSColin Finck     BOOL bRet;
1000c2c66affSColin Finck     PTRIVERTEX SafeVertex;
1001c2c66affSColin Finck     PVOID SafeMesh;
1002c2c66affSColin Finck     ULONG cbVertex, cbMesh;
1003c2c66affSColin Finck 
1004c2c66affSColin Finck     /* Validate parameters */
1005c2c66affSColin Finck     if (!pVertex || !nVertex || !pMesh || !nMesh)
1006c2c66affSColin Finck     {
1007c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_PARAMETER);
1008c2c66affSColin Finck         return FALSE;
1009c2c66affSColin Finck     }
1010c2c66affSColin Finck 
1011c2c66affSColin Finck     switch (ulMode)
1012c2c66affSColin Finck     {
1013c2c66affSColin Finck         case GRADIENT_FILL_RECT_H:
1014c2c66affSColin Finck         case GRADIENT_FILL_RECT_V:
1015c2c66affSColin Finck             cbMesh = nMesh * sizeof(GRADIENT_RECT);
1016c2c66affSColin Finck             break;
1017c2c66affSColin Finck         case GRADIENT_FILL_TRIANGLE:
1018c2c66affSColin Finck             cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE);
1019c2c66affSColin Finck             break;
1020c2c66affSColin Finck         default:
1021c2c66affSColin Finck             EngSetLastError(ERROR_INVALID_PARAMETER);
1022c2c66affSColin Finck             return FALSE;
1023c2c66affSColin Finck     }
1024c2c66affSColin Finck 
1025c2c66affSColin Finck     cbVertex = nVertex * sizeof(TRIVERTEX) ;
1026c2c66affSColin Finck     if(cbVertex + cbMesh <= cbVertex)
1027c2c66affSColin Finck     {
1028c2c66affSColin Finck         /* Overflow */
1029c2c66affSColin Finck         return FALSE ;
1030c2c66affSColin Finck     }
1031c2c66affSColin Finck 
1032c2c66affSColin Finck     /* Allocate a kernel mode buffer */
1033c2c66affSColin Finck     SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE);
1034c2c66affSColin Finck     if(!SafeVertex)
1035c2c66affSColin Finck     {
1036c2c66affSColin Finck         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
1037c2c66affSColin Finck         return FALSE;
1038c2c66affSColin Finck     }
1039c2c66affSColin Finck 
1040c2c66affSColin Finck     SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex);
1041c2c66affSColin Finck 
1042c2c66affSColin Finck     /* Copy the parameters to kernel mode */
1043c2c66affSColin Finck     _SEH2_TRY
1044c2c66affSColin Finck     {
1045c2c66affSColin Finck         ProbeForRead(pVertex, cbVertex, 1);
1046c2c66affSColin Finck         ProbeForRead(pMesh, cbMesh, 1);
1047c2c66affSColin Finck         RtlCopyMemory(SafeVertex, pVertex, cbVertex);
1048c2c66affSColin Finck         RtlCopyMemory(SafeMesh, pMesh, cbMesh);
1049c2c66affSColin Finck     }
1050c2c66affSColin Finck     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1051c2c66affSColin Finck     {
1052c2c66affSColin Finck         ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1053c2c66affSColin Finck         SetLastNtError(_SEH2_GetExceptionCode());
1054c2c66affSColin Finck         _SEH2_YIELD(return FALSE;)
1055c2c66affSColin Finck     }
1056c2c66affSColin Finck     _SEH2_END;
1057c2c66affSColin Finck 
1058c2c66affSColin Finck     /* Call the internal function */
1059c2c66affSColin Finck     bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode);
1060c2c66affSColin Finck 
1061c2c66affSColin Finck     /* Cleanup and return result */
1062c2c66affSColin Finck     ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
1063c2c66affSColin Finck     return bRet;
1064c2c66affSColin Finck }
1065c2c66affSColin Finck 
1066c2c66affSColin Finck BOOL APIENTRY
1067c2c66affSColin Finck NtGdiExtFloodFill(
1068c2c66affSColin Finck     HDC  hDC,
1069c2c66affSColin Finck     INT  XStart,
1070c2c66affSColin Finck     INT  YStart,
1071c2c66affSColin Finck     COLORREF  Color,
1072c2c66affSColin Finck     UINT  FillType)
1073c2c66affSColin Finck {
1074c2c66affSColin Finck     PDC dc;
1075c2c66affSColin Finck #if 0
1076c2c66affSColin Finck     PDC_ATTR   pdcattr;
1077c2c66affSColin Finck #endif
1078c2c66affSColin Finck     SURFACE    *psurf;
1079c2c66affSColin Finck     EXLATEOBJ  exlo;
1080c2c66affSColin Finck     BOOL       Ret = FALSE;
1081c2c66affSColin Finck     RECTL      DestRect;
1082c2c66affSColin Finck     POINTL     Pt;
1083c2c66affSColin Finck     ULONG      ConvColor;
1084*94b4b5c1Sjimtabor     PREGION    prgn;
1085c2c66affSColin Finck 
1086c2c66affSColin Finck     dc = DC_LockDc(hDC);
1087c2c66affSColin Finck     if (!dc)
1088c2c66affSColin Finck     {
1089c2c66affSColin Finck         EngSetLastError(ERROR_INVALID_HANDLE);
1090c2c66affSColin Finck         return FALSE;
1091c2c66affSColin Finck     }
1092c2c66affSColin Finck 
1093c2c66affSColin Finck     if (!dc->dclevel.pSurface)
1094c2c66affSColin Finck     {
1095c2c66affSColin Finck         Ret = TRUE;
1096c2c66affSColin Finck         goto cleanup;
1097c2c66affSColin Finck     }
1098c2c66affSColin Finck 
1099c2c66affSColin Finck #if 0
1100c2c66affSColin Finck     pdcattr = dc->pdcattr;
1101c2c66affSColin Finck #endif
1102c2c66affSColin Finck 
1103c2c66affSColin Finck     Pt.x = XStart;
1104c2c66affSColin Finck     Pt.y = YStart;
1105c2c66affSColin Finck     IntLPtoDP(dc, (LPPOINT)&Pt, 1);
1106c2c66affSColin Finck 
1107c2c66affSColin Finck     DC_vPrepareDCsForBlit(dc, &DestRect, NULL, NULL);
1108c2c66affSColin Finck 
1109c2c66affSColin Finck     psurf = dc->dclevel.pSurface;
1110*94b4b5c1Sjimtabor 
1111*94b4b5c1Sjimtabor     prgn = dc->prgnRao ? dc->prgnRao : dc->prgnVis;
1112*94b4b5c1Sjimtabor     if (prgn)
1113c2c66affSColin Finck     {
1114*94b4b5c1Sjimtabor         Ret = REGION_PtInRegion(prgn, Pt.x, Pt.y);
1115c2c66affSColin Finck         if (Ret)
1116*94b4b5c1Sjimtabor             REGION_GetRgnBox(prgn, (LPRECT)&DestRect);
1117c2c66affSColin Finck         else
1118c2c66affSColin Finck         {
1119c2c66affSColin Finck             DC_vFinishBlit(dc, NULL);
1120c2c66affSColin Finck             goto cleanup;
1121c2c66affSColin Finck         }
1122c2c66affSColin Finck     }
1123c2c66affSColin Finck     else
1124c2c66affSColin Finck     {
1125c2c66affSColin Finck         RECTL_vSetRect(&DestRect, 0, 0, psurf->SurfObj.sizlBitmap.cx, psurf->SurfObj.sizlBitmap.cy);
1126c2c66affSColin Finck     }
1127c2c66affSColin Finck 
1128c2c66affSColin Finck     if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
1129c2c66affSColin Finck     {
1130c2c66affSColin Finck        IntUpdateBoundsRect(dc, &DestRect);
1131c2c66affSColin Finck     }
1132c2c66affSColin Finck 
1133c2c66affSColin Finck     EXLATEOBJ_vInitialize(&exlo, &gpalRGB, psurf->ppal, 0, 0xffffff, 0);
1134c2c66affSColin Finck 
1135c2c66affSColin Finck     /* Only solid fills supported for now
1136c2c66affSColin Finck      * How to support pattern brushes and non standard surfaces (not offering dib functions):
1137c2c66affSColin Finck      * Version a (most likely slow): call DrvPatBlt for every pixel
1138c2c66affSColin Finck      * Version b: create a flood mask and let MaskBlt blit a masked brush */
1139c2c66affSColin Finck     ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
1140c2c66affSColin Finck     Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
1141c2c66affSColin Finck 
1142c2c66affSColin Finck     DC_vFinishBlit(dc, NULL);
1143c2c66affSColin Finck 
1144c2c66affSColin Finck     EXLATEOBJ_vCleanup(&exlo);
1145c2c66affSColin Finck 
1146c2c66affSColin Finck cleanup:
1147c2c66affSColin Finck     DC_UnlockDc(dc);
1148c2c66affSColin Finck     return Ret;
1149c2c66affSColin Finck }
1150c2c66affSColin Finck 
1151c2c66affSColin Finck /* EOF */
1152