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