xref: /reactos/win32ss/gdi/ntgdi/fillshap.c (revision 4a17d4b0)
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
IntGdiPolygon(PDC dc,PPOINT Points,int Count)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
IntGdiPolyPolygon(DC * dc,LPPOINT Points,PULONG PolyCounts,int Count)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
IntPolygon(HDC hdc,POINT * Point,int Count)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
NtGdiEllipse(HDC hDC,int Left,int Top,int Right,int Bottom)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
NtGdiPolyPolyDraw(IN HDC hDC,IN PPOINT UnsafePoints,IN PULONG UnsafeCounts,IN ULONG Count,IN INT iFunc)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
IntRectangle(PDC dc,int LeftRect,int TopRect,int RightRect,int BottomRect)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
NtGdiRectangle(HDC hDC,int LeftRect,int TopRect,int RightRect,int BottomRect)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
IntRoundRect(PDC dc,int Left,int Top,int Right,int Bottom,int xCurveDiameter,int yCurveDiameter)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
NtGdiRoundRect(HDC hDC,int LeftRect,int TopRect,int RightRect,int BottomRect,int Width,int Height)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
GreGradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode)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
NtGdiGradientFill(HDC hdc,PTRIVERTEX pVertex,ULONG nVertex,PVOID pMesh,ULONG nMesh,ULONG ulMode)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
NtGdiExtFloodFill(HDC hDC,INT XStart,INT YStart,COLORREF Color,UINT FillType)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