[WIN32K]
[reactos.git] / reactos / subsystems / win32 / win32k / objects / fillshap.c
index b362e53..327b628 100644 (file)
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include <w32k.h>
+#include <win32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
-/*
- * a couple macros to fill a single pixel or a line
- */
-#define PUTPIXEL(x,y,BrushInst)        \
-  ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
-       dc->CombinedClip,                         \
-       &BrushInst.BrushObject,                   \
-       x, y, (x)+1, y,                           \
-       &RectBounds,                              \
-       ROP2_TO_MIX(dc->Dc_Attr.jROP2));
-
-#define PUTLINE(x1,y1,x2,y2,BrushInst) \
-  ret = ret && IntEngLineTo(&BitmapObj->SurfObj, \
-       dc->CombinedClip,                         \
-       &BrushInst.BrushObject,                   \
-       x1, y1, x2, y2,                           \
-       &RectBounds,                              \
-       ROP2_TO_MIX(dc->Dc_Attr.jROP2));
+#define Rsin(d) ((d) == 0.0 ? 0.0 : ((d) == 90.0 ? 1.0 : sin(d*M_PI/180.0)))
+#define Rcos(d) ((d) == 0.0 ? 1.0 : ((d) == 90.0 ? 0.0 : cos(d*M_PI/180.0)))
+
+BOOL FASTCALL IntFillEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PBRUSH pbrush);
+BOOL FASTCALL IntDrawEllipse( PDC dc, INT XLeft, INT YLeft, INT Width, INT Height, PBRUSH pbrush);
+BOOL FASTCALL IntFillRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PBRUSH pbrush);
+BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom, INT Wellipse, INT Hellipse, PBRUSH pbrush);
 
 BOOL FASTCALL
 IntGdiPolygon(PDC    dc,
-              PPOINT UnsafePoints,
+              PPOINT Points,
               int    Count)
 {
-    BITMAPOBJ *BitmapObj;
-    PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
-    GDIBRUSHINST PenBrushInst, FillBrushInst;
+    SURFACE *psurf;
+    PBRUSH pbrLine, pbrFill;
     BOOL ret = FALSE; // default to failure
     RECTL DestRect;
     int CurrentPoint;
+    PDC_ATTR pdcattr;
+    POINTL BrushOrigin;
+//    int Left;
+//    int Top;
 
     ASSERT(dc); // caller's responsibility to pass a valid dc
 
-    if ( NULL == UnsafePoints || Count < 2 )
+    if (!Points || Count < 2 )
     {
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
 
-    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    /* FIXME - BitmapObj can be NULL!!!! don't assert but handle this case gracefully! */
-    ASSERT(BitmapObj);
+/*
+    //Find start x, y
+    Left = Points[0].x;
+    Top  = Points[0].y;
+    for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint) {
+      Left = min(Left, Points[CurrentPoint].x);
+      Top  = min(Top, Points[CurrentPoint].y);
+    }
+*/
+
+    pdcattr = dc->pdcattr;
 
     /* Convert to screen coordinates */
-    IntLPtoDP(dc, UnsafePoints, Count);
+    IntLPtoDP(dc, Points, Count);
     for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
     {
-        UnsafePoints[CurrentPoint].x += dc->w.DCOrgX;
-        UnsafePoints[CurrentPoint].y += dc->w.DCOrgY;
+        Points[CurrentPoint].x += dc->ptlDCOrig.x;
+        Points[CurrentPoint].y += dc->ptlDCOrig.y;
     }
-
-    if (PATH_IsPathOpen(dc->w.path))
-        ret = PATH_Polygon(dc, UnsafePoints, Count );
-    else
+    // No need to have path here.
     {
-        DestRect.left   = UnsafePoints[0].x;
-        DestRect.right  = UnsafePoints[0].x;
-        DestRect.top    = UnsafePoints[0].y;
-        DestRect.bottom = UnsafePoints[0].y;
+        DestRect.left   = Points[0].x;
+        DestRect.right  = Points[0].x;
+        DestRect.top    = Points[0].y;
+        DestRect.bottom = Points[0].y;
 
         for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
         {
-            DestRect.left     = min(DestRect.left, UnsafePoints[CurrentPoint].x);
-            DestRect.right    = max(DestRect.right, UnsafePoints[CurrentPoint].x);
-            DestRect.top      = min(DestRect.top, UnsafePoints[CurrentPoint].y);
-            DestRect.bottom   = max(DestRect.bottom, UnsafePoints[CurrentPoint].y);
+            DestRect.left     = min(DestRect.left, Points[CurrentPoint].x);
+            DestRect.right    = max(DestRect.right, Points[CurrentPoint].x);
+            DestRect.top      = min(DestRect.top, Points[CurrentPoint].y);
+            DestRect.bottom   = max(DestRect.bottom, Points[CurrentPoint].y);
         }
 
-        /* Now fill the polygon with the current brush. */
-        FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
-        if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
+        if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+            DC_vUpdateFillBrush(dc);
+
+        if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+            DC_vUpdateLineBrush(dc);
+
+        /* Special locking order to avoid lock-ups */
+        pbrFill = dc->dclevel.pbrFill;
+        pbrLine = dc->dclevel.pbrLine;
+        psurf = dc->dclevel.pSurface;
+        /* FIXME - psurf can be NULL!!!! don't assert but handle this case gracefully! */
+        ASSERT(psurf);
+
+        /* Now fill the polygon with the current fill brush. */
+        if (!(pbrFill->flAttrs & GDIBRUSH_IS_NULL))
         {
-            IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
-            ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(dc->Dc_Attr.jROP2), UnsafePoints, Count, DestRect );
+            BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
+            BrushOrigin.x += dc->ptlDCOrig.x;
+            BrushOrigin.y += dc->ptlDCOrig.y;
+            ret = IntFillPolygon (dc,
+                                  psurf,
+                                  &dc->eboFill.BrushObject,
+                                  Points,
+                                  Count, 
+                                  DestRect,
+                                  &BrushOrigin);
         }
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
 
-        /* get BRUSHOBJ from current pen. */
-        PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
         // Draw the Polygon Edges with the current pen ( if not a NULL pen )
-        if (PenBrushObj && !(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
+        if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
         {
             int i;
 
-            IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
-
             for (i = 0; i < Count-1; i++)
             {
 
 // DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
-//                                 UnsafePoints[0].x, UnsafePoints[0].y,
-//                                 UnsafePoints[1].x, UnsafePoints[1].y );
-
-                ret = IntEngLineTo(&BitmapObj->SurfObj,
-                                   dc->CombinedClip,
-                                   &PenBrushInst.BrushObject,
-                                   UnsafePoints[i].x,          /* From */
-                                   UnsafePoints[i].y,
-                                   UnsafePoints[i+1].x,          /* To */
-                                   UnsafePoints[i+1].y,
+//                                 Points[0].x, Points[0].y,
+//                                 Points[1].x, Points[1].y );
+
+                ret = IntEngLineTo(&psurf->SurfObj,
+                                   dc->rosdc.CombinedClip,
+                                   &dc->eboLine.BrushObject,
+                                   Points[i].x,          /* From */
+                                   Points[i].y,
+                                   Points[i+1].x,          /* To */
+                                   Points[i+1].y,
                                    &DestRect,
-                                   ROP2_TO_MIX(dc->Dc_Attr.jROP2)); /* MIX */
+                                   ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
                 if (!ret) break;
             }
             /* Close the polygon */
             if (ret)
             {
-                ret = IntEngLineTo(&BitmapObj->SurfObj,
-                                   dc->CombinedClip,
-                                   &PenBrushInst.BrushObject,
-                                   UnsafePoints[Count-1].x,          /* From */
-                                   UnsafePoints[Count-1].y,
-                                   UnsafePoints[0].x,          /* To */
-                                   UnsafePoints[0].y,
+                ret = IntEngLineTo(&psurf->SurfObj,
+                                   dc->rosdc.CombinedClip,
+                                   &dc->eboLine.BrushObject,
+                                   Points[Count-1].x, /* From */
+                                   Points[Count-1].y,
+                                   Points[0].x,       /* To */
+                                   Points[0].y,
                                    &DestRect,
-                                   ROP2_TO_MIX(dc->Dc_Attr.jROP2)); /* MIX */
+                                   ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
             }
         }
-        PENOBJ_UnlockPen(PenBrushObj);
     }
-    BITMAPOBJ_UnlockBitmap(BitmapObj);
 
     return ret;
 }
@@ -150,9 +160,12 @@ IntGdiPolygon(PDC    dc,
 BOOL FASTCALL
 IntGdiPolyPolygon(DC      *dc,
                   LPPOINT Points,
-                  LPINT   PolyCounts,
+                  PULONG  PolyCounts,
                   int     Count)
 {
+    if (PATH_IsPathOpen(dc->dclevel))
+        return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
+
     while (--Count >=0)
     {
         if (!IntGdiPolygon ( dc, Points, *PolyCounts ))
@@ -162,6 +175,8 @@ IntGdiPolyPolygon(DC      *dc,
     return TRUE;
 }
 
+
+
 /******************************************************************************/
 
 /*
@@ -174,835 +189,323 @@ IntGdiPolyPolygon(DC      *dc,
  *    This function uses optimized Bresenham's ellipse algorithm. It draws
  *    four lines of the ellipse in one pass.
  *
- * Todo
- *    Make it look like a Windows ellipse.
  */
 
-BOOL STDCALL
+BOOL APIENTRY
 NtGdiEllipse(
     HDC hDC,
-    int nLeftRect,
-    int nTopRect,
-    int nRightRect,
-    int nBottomRect)
+    int Left,
+    int Top,
+    int Right,
+    int Bottom)
 {
-    int ix, iy;
-    int A, B, C, D;
-    int da, db;
-    int NewA, NewB, NewC, NewD;
-    int nx, ny;
-    int CenterX, CenterY;
-    int RadiusX, RadiusY;
-    int Temp;
-    PGDIBRUSHOBJ FillBrush, PenBrush;
-    GDIBRUSHINST FillBrushInst, PenBrushInst;
-    BITMAPOBJ *BitmapObj;
-    RECTL RectBounds;
     PDC dc;
-    BOOL ret = TRUE, Cond1, Cond2;
-
-    /*
-     * Check the parameters.
-     */
-
-    if (nRightRect <= nLeftRect || nBottomRect <= nTopRect)
-    {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
+    PDC_ATTR pdcattr;
+    RECTL RectBounds;
+    PBRUSH pbrush;
+    BOOL ret = TRUE;
+    LONG PenWidth, PenOrigWidth;
+    LONG RadiusX, RadiusY, CenterX, CenterY;
+    PBRUSH pFillBrushObj;
+    BRUSH tmpFillBrushObj;
 
-    /*
-     * Get pointers to all necessary GDI objects.
-     */
+    if ((Left == Right) || (Top == Bottom)) return TRUE;
 
     dc = DC_LockDc(hDC);
     if (dc == NULL)
     {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return FALSE;
+       SetLastWin32Error(ERROR_INVALID_HANDLE);
+       return FALSE;
     }
-    if (dc->IsIC)
+    if (dc->dctype == DC_TYPE_INFO)
     {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
+       DC_UnlockDc(dc);
+       /* Yes, Windows really returns TRUE in this case */
+       return TRUE;
     }
 
-    FillBrush = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
-    if (NULL == FillBrush)
+    if (PATH_IsPathOpen(dc->dclevel))
     {
+        ret = PATH_Ellipse(dc, Left, Top, Right, Bottom);
         DC_UnlockDc(dc);
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
-        return FALSE;
+        return ret;
     }
 
-    PenBrush = PENOBJ_LockPen(dc->Dc_Attr.hpen);
-    if (NULL == PenBrush)
+    if (Right < Left)
     {
-        BRUSHOBJ_UnlockBrush(FillBrush);
-        DC_UnlockDc(dc);
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
-        return FALSE;
+       INT tmp = Right; Right = Left; Left = tmp;
     }
+    if (Bottom < Top)
+    {
+       INT tmp = Bottom; Bottom = Top; Top = tmp;
+    }
+
+    pdcattr = dc->pdcattr;
+
+    if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+        DC_vUpdateFillBrush(dc);
 
-    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    if (NULL == BitmapObj)
+    if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+        DC_vUpdateLineBrush(dc);
+
+    pbrush = PEN_LockPen(pdcattr->hpen);
+    if (!pbrush)
     {
-        BRUSHOBJ_UnlockBrush(FillBrush);
-        PENOBJ_UnlockPen(PenBrush);
+        DPRINT1("Ellipse Fail 1\n");
         DC_UnlockDc(dc);
         SetLastWin32Error(ERROR_INTERNAL_ERROR);
         return FALSE;
     }
 
-    IntGdiInitBrushInstance(&FillBrushInst, FillBrush, dc->XlateBrush);
-    IntGdiInitBrushInstance(&PenBrushInst, PenBrush, dc->XlatePen);
+    PenOrigWidth = PenWidth = pbrush->ptPenWidth.x;
+    if (pbrush->ulPenStyle == PS_NULL) PenWidth = 0;
+
+    if (pbrush->ulPenStyle == PS_INSIDEFRAME)
+    {
+       if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
+       if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
+       Left   += PenWidth / 2;
+       Right  -= (PenWidth - 1) / 2;
+       Top    += PenWidth / 2;
+       Bottom -= (PenWidth - 1) / 2;
+    }
 
-    RectBounds.left = nLeftRect;
-    RectBounds.right = nRightRect;
-    RectBounds.top = nTopRect;
-    RectBounds.bottom = nBottomRect;
+    if (!PenWidth) PenWidth = 1;
+    pbrush->ptPenWidth.x = PenWidth;  
 
+    RectBounds.left   = Left;
+    RectBounds.right  = Right;
+    RectBounds.top    = Top;
+    RectBounds.bottom = Bottom;
+                
     IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
+    RectBounds.left += dc->ptlDCOrig.x;
+    RectBounds.right += dc->ptlDCOrig.x;
+    RectBounds.top += dc->ptlDCOrig.y;
+    RectBounds.bottom += dc->ptlDCOrig.y;
+
+    // Setup for dynamic width and height.
+    RadiusX = max((RectBounds.right - RectBounds.left) / 2, 2); // Needs room
+    RadiusY = max((RectBounds.bottom - RectBounds.top) / 2, 2);
+    CenterX = (RectBounds.right + RectBounds.left) / 2;
+    CenterY = (RectBounds.bottom + RectBounds.top) / 2;
 
-    RectBounds.left += dc->w.DCOrgX;
-    RectBounds.right += dc->w.DCOrgX;
-    RectBounds.top += dc->w.DCOrgY;
-    RectBounds.bottom += dc->w.DCOrgY;
+    DPRINT("Ellipse 1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
+               RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
 
-    RadiusX = max((RectBounds.right - RectBounds.left) >> 1, 1);
-    RadiusY = max((RectBounds.bottom - RectBounds.top) >> 1, 1);
-    CenterX = RectBounds.left + RadiusX;
-    CenterY = RectBounds.top + RadiusY;
+    DPRINT("Ellipse 2: XLeft: %d, YLeft: %d, Width: %d, Height: %d\n",
+               CenterX - RadiusX, CenterY + RadiusY, RadiusX*2, RadiusY*2);
 
-    if (RadiusX > RadiusY)
+    pFillBrushObj = BRUSH_LockBrush(pdcattr->hbrush);
+    if (NULL == pFillBrushObj)   
     {
-        nx = RadiusX;
-        ny = RadiusY;
+        DPRINT1("FillEllipse Fail\n");
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        ret = FALSE;
     }
     else
     {
-        nx = RadiusY;
-        ny = RadiusX;
-    }
-
-    da = -1;
-    db = 0xFFFF;
-    ix = 0;
-    iy = nx * 64;
-    NewA = 0;
-    NewB = (iy + 32) >> 6;
-    NewC = 0;
-    NewD = (NewB * ny) / nx;
-
-    do {
-        A = NewA;
-        B = NewB;
-        C = NewC;
-        D = NewD;
-
-        ix += iy / nx;
-        iy -= ix / nx;
-        NewA = (ix + 32) >> 6;
-        NewB = (iy + 32) >> 6;
-        NewC = (NewA * ny) / nx;
-        NewD = (NewB * ny) / nx;
-
-        if (RadiusX > RadiusY)
-        {
-            Temp = A; A = C; C = Temp;
-            Temp = B; B = D; D = Temp;
-            Cond1 = ((C != NewA) || (B != NewD)) && (NewC <= NewD);
-            Cond2 = ((D != NewB) || (A != NewC)) && (NewC <= B);
-        }
-        else
-        {
-            Cond1 = ((C != NewC) || (B != NewB)) && (NewA <= NewB);
-            Cond2 = ((D != NewD) || (A != NewA)) && (NewA <= B);
-        }
-
-        /*
-         * Draw the lines going from inner to outer (+ mirrored).
-         */
-
-        if ((A > da) && (A < db))
-        {
-            PUTLINE(CenterX - D, CenterY + A, CenterX + D, CenterY + A, FillBrushInst);
-            if (A)
-            {
-                PUTLINE(CenterX - D, CenterY - A, CenterX + D, CenterY - A, FillBrushInst);
-            }
-            da = A;
-        }
-
-        /*
-         * Draw the lines going from outer to inner (+ mirrored).
-         */
-
-        if ((B < db) && (B > da))
-        {
-            PUTLINE(CenterX - C, CenterY + B, CenterX + C, CenterY + B, FillBrushInst);
-            PUTLINE(CenterX - C, CenterY - B, CenterX + C, CenterY - B, FillBrushInst);
-            db = B;
-        }
-
-        /*
-         * Draw the pixels on the margin.
-         */
-
-        if (Cond1)
-        {
-            PUTPIXEL(CenterX + C, CenterY + B, PenBrushInst);
-            if (C)
-                PUTPIXEL(CenterX - C, CenterY + B, PenBrushInst);
-            if (B)
-            {
-                PUTPIXEL(CenterX + C, CenterY - B, PenBrushInst);
-                if (C)
-                    PUTPIXEL(CenterX - C, CenterY - B, PenBrushInst);
-            }
-        }
-
-        if (Cond2)
-        {
-            PUTPIXEL(CenterX + D, CenterY + A, PenBrushInst);
-            if (D)
-                PUTPIXEL(CenterX - D, CenterY + A, PenBrushInst);
-            if (A)
-            {
-                PUTPIXEL(CenterX + D, CenterY - A, PenBrushInst);
-                if (D)
-                    PUTPIXEL(CenterX - D, CenterY - A, PenBrushInst);
-            }
-        }
-    } while (B > A);
-
-    BITMAPOBJ_UnlockBitmap(BitmapObj);
-    BRUSHOBJ_UnlockBrush(FillBrush);
-    PENOBJ_UnlockPen(PenBrush);
+        RtlCopyMemory(&tmpFillBrushObj, pFillBrushObj, sizeof(tmpFillBrushObj));
+//        tmpFillBrushObj.ptOrigin.x += RectBounds.left - Left;
+//        tmpFillBrushObj.ptOrigin.y += RectBounds.top - Top;
+        tmpFillBrushObj.ptOrigin.x += dc->ptlDCOrig.x;
+        tmpFillBrushObj.ptOrigin.y += dc->ptlDCOrig.y;
+        ret = IntFillEllipse( dc,
+                              CenterX - RadiusX,
+                              CenterY - RadiusY,
+                              RadiusX*2, // Width
+                              RadiusY*2, // Height
+                              &tmpFillBrushObj);
+        BRUSH_UnlockBrush(pFillBrushObj);
+    }
+
+    if (ret)
+       ret = IntDrawEllipse( dc,
+                             CenterX - RadiusX,
+                             CenterY - RadiusY,
+                             RadiusX*2, // Width
+                             RadiusY*2, // Height
+                             pbrush);
+
+    pbrush->ptPenWidth.x = PenOrigWidth;
+    PEN_UnlockPen(pbrush);
     DC_UnlockDc(dc);
-
+    DPRINT("Ellipse Exit.\n");
     return ret;
 }
 
-typedef struct tagSHAPEPOINT
-{
-    int X;
-    int Y;
-    int Type;
-} SHAPEPOINT, *PSHAPEPOINT;
-
-#define SHAPEPOINT_TYPE_CIRCLE     'C'
-#define SHAPEPOINT_TYPE_LINE_RIGHT 'R' /* Fill at right side of line */
-#define SHAPEPOINT_TYPE_LINE_LEFT  'L' /* Fill at left side of line */
-
-#define SETPOINT(x, y, type) \
-  ShapePoints[*PointCount].X = (x); \
-  ShapePoints[*PointCount].Y = (y); \
-  ShapePoints[*PointCount].Type = (type); \
-  (*PointCount)++
-
-#define SETCIRCLEPOINT(x, y) \
-  SETPOINT(x, y, SHAPEPOINT_TYPE_CIRCLE)
-
-#ifdef TODO
-STATIC VOID
-FASTCALL
-CirclePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
-             int Right, int Bottom)
-{
-    int X, X18, X27, X36, X45;
-    int Y, Y14, Y23, Y58, Y67;
-    int d, Radius;
-    BOOL Even;
-
-    Even = (0 == (Right - Left) % 2);
-    Right--;
-    Bottom--;
-    Radius = (Right - Left) >> 1;
+#if 0
 
-    if (Even)
-    {
-        X = 0;
-        Y = Radius;
-        d = 2 - Radius;
-        X18 = Right;
-        X27 = ((Left + Right) >> 1) + 1;
-        X36 = (Left + Right) >> 1;
-        X45 = Left;
-        Y14 = Top + Radius;
-        Y23 = Top;
-        Y58 = Top + Radius + 1;
-        Y67 = Top + (Right - Left);
-        ShapePoints[*PointCount].X = X27;
-        SETCIRCLEPOINT(X27, Y23);
-        SETCIRCLEPOINT(X36, Y23);
-        SETCIRCLEPOINT(X18, Y14);
-        SETCIRCLEPOINT(X45, Y14);
-        SETCIRCLEPOINT(X18, Y58);
-        SETCIRCLEPOINT(X45, Y58);
-        SETCIRCLEPOINT(X27, Y67);
-        SETCIRCLEPOINT(X36, Y67);
-    }
-    else
-    {
-        X = 0;
-        Y = Radius;
-        d = 1 - Radius;
-        X18 = Right;
-        X27 = (Left + Right) >> 1;
-        X36 = (Left + Right) >> 1;
-        X45 = Left;
-        Y14 = Top + Radius;
-        Y23 = Top;
-        Y58 = Top + Radius;
-        Y67 = Top + (Right - Left);
-        SETCIRCLEPOINT(X27, Y23);
-        SETCIRCLEPOINT(X45, Y14);
-        SETCIRCLEPOINT(X18, Y58);
-        SETCIRCLEPOINT(X27, Y67);
-    }
+//When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
+//even-numbered polygon sides on each scan line. That is, GDI fills the area between the
+//first and second side, between the third and fourth side, and so on.
 
-    while (X < Y)
-    {
-        if (d < 0)
-        {
-            d += (X << 1) + (Even ? 4 : 3);
+//WINDING Selects winding mode (fills any region with a nonzero winding value).
+//When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
+//This value is defined as the number of times a pen used to draw the polygon would go around the region.
+//The direction of each edge of the polygon is important.
 
-            X27++;
-            X36--;
-            Y14--;
-            Y58++;
-        }
-        else
-        {
-            d += ((X - Y) << 1) + 5;
-            Y--;
-
-            Y23++;
-            Y67--;
-            X18--;
-            X45++;
-            X27++;
-            X36--;
-            Y14--;
-            Y58++;
-        }
-        X++;
-
-        SETCIRCLEPOINT(X27, Y23);
-        SETCIRCLEPOINT(X36, Y23);
-        SETCIRCLEPOINT(X18, Y14);
-        SETCIRCLEPOINT(X45, Y14);
-        SETCIRCLEPOINT(X18, Y58);
-        SETCIRCLEPOINT(X45, Y58);
-        SETCIRCLEPOINT(X27, Y67);
-        SETCIRCLEPOINT(X36, Y67);
-    }
-}
+extern BOOL FillPolygon(PDC dc,
+                            SURFOBJ *SurfObj,
+                            PBRUSHOBJ BrushObj,
+                            MIX RopMode,
+                            CONST PPOINT Points,
+                            int Count,
+                            RECTL BoundRect);
 
-STATIC VOID
-LinePoints(UINT *PointCount, PSHAPEPOINT ShapePoints, int Left, int Top,
-           int Right, int Bottom, int XTo, int YTo, BOOL Start)
-{
-    LONG x, y, deltax, deltay, i, xchange, ychange, error;
-    int Type;
+#endif
 
-    x = (Right + Left) >> 1;
-    y = (Bottom + Top) >> 1;
-    deltax = XTo - x;
-    deltay = YTo - y;
 
-    if (deltax < 0)
-    {
-        xchange = -1;
-        deltax = - deltax;
-        x--;
-    }
-    else
-    {
-        xchange = 1;
-    }
+ULONG_PTR
+APIENTRY
+NtGdiPolyPolyDraw( IN HDC hDC,
+                   IN PPOINT UnsafePoints,
+                   IN PULONG UnsafeCounts,
+                   IN ULONG Count,
+                   IN INT iFunc )
+{
+    DC *dc;
+    PVOID pTemp;
+    LPPOINT SafePoints;
+    PULONG SafeCounts;
+    NTSTATUS Status = STATUS_SUCCESS;
+    BOOL Ret = TRUE;
+    INT nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
 
-    if (deltay < 0)
-    {
-        ychange = -1;
-        deltay = - deltay;
-        y--;
-        Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
-    }
-    else
+    if (!UnsafePoints || !UnsafeCounts ||
+        Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
     {
-        ychange = 1;
-        Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
+        /* Windows doesn't set last error */
+        return FALSE;
     }
 
-    if (y == YTo)
-    {
-        for (i = x; i <= XTo; i++)
-        {
-            SETPOINT(i, y, Type);
-        }
-    }
-    else if (x == XTo)
-    {
-        for (i = y; i <= YTo; i++)
-        {
-            SETPOINT(x, i, Type);
-        }
-    }
-    else
+    _SEH2_TRY
     {
-        error = 0;
+        ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
+        ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
 
-        if (deltax < deltay)
-        {
-            for (i = 0; i < deltay; i++)
-            {
-                SETPOINT(x, y, Type);
-                y = y + ychange;
-                error = error + deltax;
-
-                if (deltay <= error)
-                {
-                    x = x + xchange;
-                    error = error - deltay;
-                }
-            }
-        }
-        else
+        /* Count points and validate poligons */
+        for (i = 0; i < Count; i++)
         {
-            for (i = 0; i < deltax; i++)
+            if (UnsafeCounts[i] < 2)
             {
-                SETPOINT(x, y, Type);
-                x = x + xchange;
-                error = error + deltay;
-                if (deltax <= error)
-                {
-                    y = y + ychange;
-                    error = error - deltax;
-                }
+                nInvalid++;
             }
+            nPoints += UnsafeCounts[i];
+            nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
         }
     }
-}
-
-STATIC int
-CDECL
-CompareShapePoints(const void *pv1, const void *pv2)
-{
-    if (((const PSHAPEPOINT) pv1)->Y < ((const PSHAPEPOINT) pv2)->Y)
-    {
-        return -1;
-    }
-    else if (((const PSHAPEPOINT) pv2)->Y < ((const PSHAPEPOINT) pv1)->Y)
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        return +1;
+        Status = _SEH2_GetExceptionCode();
     }
-    else if (((const PSHAPEPOINT) pv1)->X < ((const PSHAPEPOINT) pv2)->X)
-    {
-        return -1;
-    }
-    else if (((const PSHAPEPOINT) pv2)->X < ((const PSHAPEPOINT) pv1)->X)
-    {
-        return +1;
-    }
-    else
-    {
-        return 0;
-    }
-}
-#endif
-
-
-BOOL
-STDCALL
-NtGdiPie(HDC  hDC,
-         int  Left,
-         int  Top,
-         int  Right,
-         int  Bottom,
-         int  XRadialStart,
-         int  YRadialStart,
-         int  XRadialEnd,
-         int  YRadialEnd)
-{
-#ifdef TODO
-    PDC dc;
-    RECTL RectBounds;
-    SURFOBJ *SurfObj;
-    BRUSHOBJ PenBrushObj;
-    PBRUSHOBJ FillBrushObj;
-    PSHAPEPOINT ShapePoints;
-    UINT Point, PointCount;
-    BOOL ret = TRUE;
-    int Y, CircleStart, CircleEnd, LineStart, LineEnd;
-    BOOL FullFill;
+    _SEH2_END;
 
-    if (Right <= Left || Bottom <= Top)
+    if (!NT_SUCCESS(Status))
     {
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
+        /* Windows doesn't set last error */
         return FALSE;
     }
 
-    if (Right - Left != Bottom - Top)
+    if (nPoints == 0 || nPoints < nMaxPoints)
     {
-        UNIMPLEMENTED;
+        /* If all polygon counts are zero, or we have overflow,
+           return without setting a last error code. */
+        return FALSE;
     }
 
-    dc = DC_LockDc ( hDC );
-    if (NULL == dc)
+    if (nInvalid != 0)
     {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
+        /* If at least one poly count is 0 or 1, fail */
+        SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-    if (dc->IsIC)
-    {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
-    }
 
-    FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
-    if (NULL == FillBrushObj)
+    /* Allocate one buffer for both counts and points */
+    pTemp = ExAllocatePoolWithTag(PagedPool,
+                                  Count * sizeof(ULONG) + nPoints * sizeof(POINT),
+                                  TAG_SHAPE);
+    if (!pTemp)
     {
-        DC_UnlockDc(dc);
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
 
-    Left += dc->w.DCOrgX;
-    Right += dc->w.DCOrgX;
-    Top += dc->w.DCOrgY;
-    Bottom += dc->w.DCOrgY;
-    XRadialStart += dc->w.DCOrgX;
-    YRadialStart += dc->w.DCOrgY;
-    XRadialEnd += dc->w.DCOrgX;
-    YRadialEnd += dc->w.DCOrgY;
+    SafeCounts = pTemp;
+    SafePoints = (PVOID)(SafeCounts + Count);
 
-    RectBounds.left = Left;
-    RectBounds.right = Right;
-    RectBounds.top = Top;
-    RectBounds.bottom = Bottom;
-
-    SurfObj = (SURFOBJ*) AccessUserObject((ULONG)dc->Surface);
-    HPenToBrushObj(&PenBrushObj, dc->Dc_Attr.hpen);
-
-    /* Number of points for the circle is 4 * sqrt(2) * Radius, start
-       and end line have at most Radius points, so allocate at least
-       that much */
-    ShapePoints = ExAllocatePoolWithTag(PagedPool, 8 * (Right - Left + 1) / 2 * sizeof(SHAPEPOINT), TAG_SHAPE);
-    if (NULL == ShapePoints)
+    _SEH2_TRY
     {
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        DC_UnlockDc(dc);
-
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
+        /* Pointers already probed! */
+        RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
+        RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
     }
-
-    if (Left == Right)
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        PUTPIXEL(Left, Top, &PenBrushObj);
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        DC_UnlockDc(dc);
-
-        return ret;
+        Status = _SEH2_GetExceptionCode();
     }
+    _SEH2_END;
 
-    PointCount = 0;
-    CirclePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom);
-    LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
-               XRadialStart, YRadialStart, TRUE);
-    LinePoints(&PointCount, ShapePoints, Left, Top, Right, Bottom,
-               XRadialEnd, YRadialEnd, FALSE);
-    ASSERT(PointCount <= 8 * (Right - Left + 1) / 2);
-    EngSort((PBYTE) ShapePoints, sizeof(SHAPEPOINT), PointCount, CompareShapePoints);
-
-    FullFill = TRUE;
-    Point = 0;
-    while (Point < PointCount)
+    if (!NT_SUCCESS(Status))
     {
-        Y = ShapePoints[Point].Y;
-
-        /* Skip any line pixels before circle */
-        while (Point < PointCount && ShapePoints[Point].Y == Y
-                && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
-        {
-            Point++;
-        }
-
-        /* Handle left side of circle */
-        if (Point < PointCount && ShapePoints[Point].Y == Y)
-        {
-            CircleStart = ShapePoints[Point].X;
-            Point++;
-            while (Point < PointCount && ShapePoints[Point].Y == Y
-                    && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
-                    && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
-            {
-                Point++;
-            }
-            CircleEnd = ShapePoints[Point - 1].X;
-
-            PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
-        }
-
-        /* Handle line(s) (max 2) inside the circle */
-        while (Point < PointCount && ShapePoints[Point].Y == Y
-                && SHAPEPOINT_TYPE_CIRCLE != ShapePoints[Point].Type)
-        {
-            LineStart = ShapePoints[Point].X;
-            Point++;
-            while (Point < PointCount && ShapePoints[Point].Y == Y
-                    && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
-                    && ShapePoints[Point].Type == ShapePoints[Point - 1].Type)
-            {
-                Point++;
-            }
-            LineEnd = ShapePoints[Point - 1].X;
-
-            PUTLINE(LineStart, Y, LineEnd + 1, Y, &PenBrushObj);
-        }
-
-        /* Handle right side of circle */
-        while (Point < PointCount && ShapePoints[Point].Y == Y
-                && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
-        {
-            CircleStart = ShapePoints[Point].X;
-            Point++;
-            while (Point < PointCount && ShapePoints[Point].Y == Y
-                    && ShapePoints[Point].X == ShapePoints[Point - 1].X + 1
-                    && SHAPEPOINT_TYPE_CIRCLE == ShapePoints[Point].Type)
-            {
-                Point++;
-            }
-            CircleEnd = ShapePoints[Point - 1].X;
-
-            PUTLINE(CircleStart, Y, CircleEnd + 1, Y, &PenBrushObj);
-        }
-
-        /* Skip any line pixels after circle */
-        while (Point < PointCount && ShapePoints[Point].Y == Y)
-        {
-            Point++;
-        }
+        ExFreePoolWithTag(pTemp, TAG_SHAPE);
+        return FALSE;
     }
 
-    ExFreePool(ShapePoints);
-    BRUSHOBJ_UnlockBrush(FillBrushObj);
-    DC_UnlockDc(dc);
-
-    return ret;
-#else
-    return TRUE;
-#endif
-}
-
-#if 0
-
-//When the fill mode is ALTERNATE, GDI fills the area between odd-numbered and
-//even-numbered polygon sides on each scan line. That is, GDI fills the area between the
-//first and second side, between the third and fourth side, and so on.
-
-//WINDING Selects winding mode (fills any region with a nonzero winding value).
-//When the fill mode is WINDING, GDI fills any region that has a nonzero winding value.
-//This value is defined as the number of times a pen used to draw the polygon would go around the region.
-//The direction of each edge of the polygon is important.
-
-extern BOOL FillPolygon(PDC dc,
-                            SURFOBJ *SurfObj,
-                            PBRUSHOBJ BrushObj,
-                            MIX RopMode,
-                            CONST PPOINT Points,
-                            int Count,
-                            RECTL BoundRect);
-
-#endif
-
-
-ULONG_PTR
-STDCALL
-NtGdiPolyPolyDraw( IN HDC hDC,
-                   IN PPOINT Points,
-                   IN PULONG PolyCounts,
-                   IN ULONG Count,
-                   IN INT iFunc )
-{
-    DC *dc;
-    LPPOINT Safept;
-    LPINT SafePolyPoints;
-    NTSTATUS Status = STATUS_SUCCESS;
-    BOOL Ret = TRUE;
-    INT nPoints, nEmpty, nInvalid, i;
-
+    /* Special handling for GdiPolyPolyRgn */
     if (iFunc == GdiPolyPolyRgn)
     {
-        return (ULONG_PTR) GdiCreatePolyPolygonRgn((CONST PPOINT)  Points,
-                (CONST PINT)  PolyCounts,
-                Count,
-                (INT) hDC);
+        HRGN hRgn;
+        hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC);
+        ExFreePoolWithTag(pTemp, TAG_SHAPE);
+        return (ULONG_PTR)hRgn;
     }
+
     dc = DC_LockDc(hDC);
     if (!dc)
     {
         SetLastWin32Error(ERROR_INVALID_HANDLE);
+        ExFreePool(pTemp);
         return FALSE;
     }
-    if (dc->IsIC)
+
+    if (dc->dctype == DC_TYPE_INFO)
     {
         DC_UnlockDc(dc);
+        ExFreePool(pTemp);
         /* Yes, Windows really returns TRUE in this case */
         return TRUE;
     }
 
-    if (Count > 0)
-    {
-        _SEH_TRY
-        {
-            ProbeForRead(Points,
-                         Count * sizeof(POINT),
-                         1);
-            ProbeForRead(PolyCounts,
-                         Count * sizeof(INT),
-                         1);
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (!NT_SUCCESS(Status))
-        {
-            DC_UnlockDc(dc);
-            SetLastNtError(Status);
-            return FALSE;
-        }
-
-        SafePolyPoints = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_SHAPE);
-        if (!SafePolyPoints)
-        {
-            DC_UnlockDc(dc);
-            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-
-        _SEH_TRY
-        {
-            /* pointers already probed! */
-            RtlCopyMemory(SafePolyPoints,
-                          PolyCounts,
-                          Count * sizeof(INT));
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (!NT_SUCCESS(Status))
-        {
-            DC_UnlockDc(dc);
-            ExFreePool(SafePolyPoints);
-            SetLastNtError(Status);
-            return FALSE;
-        }
-        /* validate poligons */
-        nPoints = 0;
-        nEmpty = 0;
-        nInvalid = 0;
-        for (i = 0; i < Count; i++)
-        {
-            if (SafePolyPoints[i] == 0)
-            {
-                nEmpty++;
-            }
-            if (SafePolyPoints[i] == 1)
-            {
-                nInvalid++;
-            }
-            nPoints += SafePolyPoints[i];
-        }
-
-        if (nEmpty == Count)
-        {
-            /* if all polygon counts are zero, return without setting a last error code. */
-            ExFreePool(SafePolyPoints);
-            return FALSE;
-        }
-        if (nInvalid != 0)
-        {
-            /* if at least one poly count is 1, fail */
-            ExFreePool(SafePolyPoints);
-            SetLastWin32Error(ERROR_INVALID_PARAMETER);
-            return FALSE;
-        }
-
-        Safept = ExAllocatePoolWithTag(PagedPool, nPoints * sizeof(POINT), TAG_SHAPE);
-        if (!Safept)
-        {
-            DC_UnlockDc(dc);
-            ExFreePool(SafePolyPoints);
-            SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-            return FALSE;
-        }
-
-        _SEH_TRY
-        {
-            /* pointers already probed! */
-            RtlCopyMemory(Safept,
-                          Points,
-                          nPoints * sizeof(POINT));
-        }
-        _SEH_HANDLE
-        {
-            Status = _SEH_GetExceptionCode();
-        }
-        _SEH_END;
-
-        if (!NT_SUCCESS(Status))
-        {
-            DC_UnlockDc(dc);
-            ExFreePool(SafePolyPoints);
-            ExFreePool(Safept);
-            SetLastNtError(Status);
-            return FALSE;
-        }
-    }
-    else
-    {
-        DC_UnlockDc(dc);
-        SetLastWin32Error(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
+    /* Perform the actual work */
     switch (iFunc)
     {
         case GdiPolyPolygon:
-            Ret = IntGdiPolyPolygon(dc, Safept, SafePolyPoints, Count);
+            Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
             break;
         case GdiPolyPolyLine:
-            Ret = IntGdiPolyPolyline(dc, Safept, (LPDWORD) SafePolyPoints, Count);
+            Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
             break;
         case GdiPolyBezier:
-            Ret = IntGdiPolyBezier(dc, Safept, *PolyCounts);
+            Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
             break;
         case GdiPolyLineTo:
-            Ret = IntGdiPolylineTo(dc, Safept, *PolyCounts);
+            Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
             break;
         case GdiPolyBezierTo:
-            Ret = IntGdiPolyBezierTo(dc, Safept, *PolyCounts);
+            Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
             break;
         default:
             SetLastWin32Error(ERROR_INVALID_PARAMETER);
             Ret = FALSE;
     }
-    ExFreePool(SafePolyPoints);
-    ExFreePool(Safept);
+
+    /* Cleanup and return */
     DC_UnlockDc(dc);
+    ExFreePool(pTemp);
 
-    return (ULONG_PTR) Ret;
+    return (ULONG_PTR)Ret;
 }
 
 
@@ -1014,116 +517,142 @@ IntRectangle(PDC dc,
              int RightRect,
              int BottomRect)
 {
-    BITMAPOBJ *BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
-    GDIBRUSHINST PenBrushInst, FillBrushInst;
+    SURFACE *psurf = NULL;
+    PBRUSH pbrLine, pbrFill;
     BOOL       ret = FALSE; // default to failure
     RECTL      DestRect;
     MIX        Mix;
+    PDC_ATTR pdcattr;
+    POINTL BrushOrigin;
 
     ASSERT ( dc ); // caller's responsibility to set this up
-    /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
-    ASSERT ( BitmapObj );
 
-    if ( PATH_IsPathOpen(dc->w.path) )
+    pdcattr = dc->pdcattr;
+
+    /* Do we rotate or shear? */
+    if (!(dc->dclevel.mxWorldToDevice.flAccel & MX_SCALE))
     {
-        ret = PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
+
+        POINTL DestCoords[4];
+        ULONG  PolyCounts = 4;
+        DestCoords[0].x = DestCoords[3].x = LeftRect;
+        DestCoords[0].y = DestCoords[1].y = TopRect;
+        DestCoords[1].x = DestCoords[2].x = RightRect;
+        DestCoords[2].y = DestCoords[3].y = BottomRect;
+        // Use IntGdiPolyPolygon so to support PATH.
+        return IntGdiPolyPolygon(dc, DestCoords, &PolyCounts, 1);
     }
-    else
+    // Rectangle Path only.
+    if ( PATH_IsPathOpen(dc->dclevel) )
     {
-        LeftRect   += dc->w.DCOrgX;
-        RightRect  += dc->w.DCOrgX - 1;
-        TopRect    += dc->w.DCOrgY;
-        BottomRect += dc->w.DCOrgY - 1;
+        return PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
+    }
 
-        DestRect.left = LeftRect;
-        DestRect.right = RightRect;
-        DestRect.top = TopRect;
-        DestRect.bottom = BottomRect;
+    DestRect.left = LeftRect;
+    DestRect.right = RightRect;
+    DestRect.top = TopRect;
+    DestRect.bottom = BottomRect;
 
-        FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
+    IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
 
-        if ( FillBrushObj )
-        {
-            if (!(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
-            {
-                IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
-                ret = IntEngBitBlt(&BitmapObj->SurfObj,
-                                   NULL,
-                                   NULL,
-                                   dc->CombinedClip,
-                                   NULL,
-                                   &DestRect,
-                                   NULL,
-                                   NULL,
-                                   &FillBrushInst.BrushObject,
-                                   NULL,
-                                   ROP3_TO_ROP4(PATCOPY));
-            }
-        }
+    DestRect.left   += dc->ptlDCOrig.x;
+    DestRect.right  += dc->ptlDCOrig.x;
+    DestRect.top    += dc->ptlDCOrig.y;
+    DestRect.bottom += dc->ptlDCOrig.y;
+
+    /* In GM_COMPATIBLE, don't include bottom and right edges */
+    if (pdcattr->iGraphicsMode == GM_COMPATIBLE)
+    {
+        DestRect.right--;
+        DestRect.bottom--;
+    }
+
+    if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+        DC_vUpdateFillBrush(dc);
 
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
+    if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+        DC_vUpdateLineBrush(dc);
 
-        /* get BRUSHOBJ from current pen. */
-        PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
-        if (PenBrushObj == NULL)
+    pbrFill = dc->dclevel.pbrFill;
+    pbrLine = dc->dclevel.pbrLine;
+    if (!pbrLine)
+    {
+        ret = FALSE;
+        goto cleanup;
+    }
+    psurf = dc->dclevel.pSurface;
+    if (!psurf)
+    {
+        ret = FALSE;
+        goto cleanup;
+    }
+
+    if (pbrFill)
+    {
+        if (!(pbrFill->flAttrs & GDIBRUSH_IS_NULL))
         {
-            SetLastWin32Error(ERROR_INVALID_HANDLE);
-            BITMAPOBJ_UnlockBitmap(BitmapObj);
-            return FALSE;
+            BrushOrigin = *((PPOINTL)&pbrFill->ptOrigin);
+            BrushOrigin.x += dc->ptlDCOrig.x;
+            BrushOrigin.y += dc->ptlDCOrig.y;
+            ret = IntEngBitBlt(&psurf->SurfObj,
+                               NULL,
+                               NULL,
+                               dc->rosdc.CombinedClip,
+                               NULL,
+                               &DestRect,
+                               NULL,
+                               NULL,
+                               &dc->eboFill.BrushObject,
+                               &BrushOrigin,
+                               ROP3_TO_ROP4(PATCOPY));
         }
+    }
 
-        IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
+    // Draw the rectangle with the current pen
 
-        // Draw the rectangle with the current pen
+    ret = TRUE; // change default to success
 
-        ret = TRUE; // change default to success
+    if (!(pbrLine->flAttrs & GDIBRUSH_IS_NULL))
+    {
+        Mix = ROP2_TO_MIX(pdcattr->jROP2);
+        ret = ret && IntEngLineTo(&psurf->SurfObj,
+                                  dc->rosdc.CombinedClip,
+                                  &dc->eboLine.BrushObject,
+                                  DestRect.left, DestRect.top, DestRect.right, DestRect.top,
+                                  &DestRect, // Bounding rectangle
+                                  Mix);
 
-        if (!(PenBrushObj->flAttrs & GDIBRUSH_IS_NULL))
-        {
-            Mix = ROP2_TO_MIX(dc->Dc_Attr.jROP2);
-            ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
-                                      dc->CombinedClip,
-                                      &PenBrushInst.BrushObject,
-                                      LeftRect, TopRect, RightRect, TopRect,
-                                      &DestRect, // Bounding rectangle
-                                      Mix);
-
-            ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
-                                      dc->CombinedClip,
-                                      &PenBrushInst.BrushObject,
-                                      RightRect, TopRect, RightRect, BottomRect,
-                                      &DestRect, // Bounding rectangle
-                                      Mix);
-
-            ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
-                                      dc->CombinedClip,
-                                      &PenBrushInst.BrushObject,
-                                      RightRect, BottomRect, LeftRect, BottomRect,
-                                      &DestRect, // Bounding rectangle
-                                      Mix);
-
-            ret = ret && IntEngLineTo(&BitmapObj->SurfObj,
-                                      dc->CombinedClip,
-                                      &PenBrushInst.BrushObject,
-                                      LeftRect, BottomRect, LeftRect, TopRect,
-                                      &DestRect, // Bounding rectangle
-                                      Mix);
-        }
+        ret = ret && IntEngLineTo(&psurf->SurfObj,
+                                  dc->rosdc.CombinedClip,
+                                  &dc->eboLine.BrushObject,
+                                  DestRect.right, DestRect.top, DestRect.right, DestRect.bottom,
+                                  &DestRect, // Bounding rectangle
+                                  Mix);
 
-        PENOBJ_UnlockPen(PenBrushObj);
-    }
+        ret = ret && IntEngLineTo(&psurf->SurfObj,
+                                  dc->rosdc.CombinedClip,
+                                  &dc->eboLine.BrushObject,
+                                  DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom,
+                                  &DestRect, // Bounding rectangle
+                                  Mix);
 
-    BITMAPOBJ_UnlockBitmap(BitmapObj);
+        ret = ret && IntEngLineTo(&psurf->SurfObj,
+                                  dc->rosdc.CombinedClip,
+                                  &dc->eboLine.BrushObject,
+                                  DestRect.left, DestRect.bottom, DestRect.left, DestRect.top,
+                                  &DestRect, // Bounding rectangle
+                                  Mix);
+    }
 
+cleanup:
     /* Move current position in DC?
        MSDN: The current position is neither used nor updated by Rectangle. */
 
-    return TRUE;
+    return ret;
 }
 
 BOOL
-STDCALL
+APIENTRY
 NtGdiRectangle(HDC  hDC,
                int  LeftRect,
                int  TopRect,
@@ -1139,7 +668,7 @@ NtGdiRectangle(HDC  hDC,
         SetLastWin32Error(ERROR_INVALID_HANDLE);
         return FALSE;
     }
-    if (dc->IsIC)
+    if (dc->dctype == DC_TYPE_INFO)
     {
         DC_UnlockDc(dc);
         /* Yes, Windows really returns TRUE in this case */
@@ -1157,273 +686,124 @@ BOOL
 FASTCALL
 IntRoundRect(
     PDC  dc,
-    int  left,
-    int  top,
-    int  right,
-    int  bottom,
+    int  Left,
+    int  Top,
+    int  Right,
+    int  Bottom,
     int  xCurveDiameter,
     int  yCurveDiameter)
 {
-    BITMAPOBJ   *BitmapObj;
-    PGDIBRUSHOBJ   PenBrushObj, FillBrushObj;
-    GDIBRUSHINST FillBrushInst, PenBrushInst;
-    RECTL      RectBounds;
-    int potential_steps;
-    int i, col, row, width, height, x1, x1start, x2, x2start, y1, y2;
-    int xradius, yradius;
-    //float aspect_square;
-    long a_square, b_square,
-    two_a_square, two_b_square,
-    four_a_square, four_b_square,
-    d, dinc, ddec;
-    BOOL first,
-    ret = TRUE; // default to success
+    PDC_ATTR pdcattr;
+    PBRUSH   pbrushLine, pbrushFill;
+    RECTL RectBounds;
+    LONG PenWidth, PenOrigWidth;
+    BOOL ret = TRUE; // default to success
+    BRUSH brushTemp;
 
     ASSERT ( dc ); // caller's responsibility to set this up
 
-    if ( PATH_IsPathOpen(dc->w.path) )
-        return PATH_RoundRect ( dc, left, top, right, bottom,
+    if ( PATH_IsPathOpen(dc->dclevel) )
+        return PATH_RoundRect ( dc, Left, Top, Right, Bottom,
                                 xCurveDiameter, yCurveDiameter );
 
-    xradius = xCurveDiameter >> 1;
-    yradius = yCurveDiameter >> 1;
-
-    left += dc->w.DCOrgX;
-    right += dc->w.DCOrgX;
-    top += dc->w.DCOrgY;
-    bottom += dc->w.DCOrgY;
+    if ((Left == Right) || (Top == Bottom)) return TRUE;
 
-    RectBounds.left = left;
-    RectBounds.right = right;
-    RectBounds.top = top;
-    RectBounds.bottom = bottom;
+    xCurveDiameter = max(abs( xCurveDiameter ), 1);
+    yCurveDiameter = max(abs( yCurveDiameter ), 1);
 
-    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    if (!BitmapObj)
+    if (Right < Left)
     {
-        /* Nothing to do, as we don't have a bitmap */
-        SetLastWin32Error(ERROR_INTERNAL_ERROR);
-        return FALSE;
-    }
-
-    FillBrushObj = BRUSHOBJ_LockBrush(dc->Dc_Attr.hbrush);
-    if (FillBrushObj)
-    {
-        if (FillBrushObj->flAttrs & GDIBRUSH_IS_NULL)
-        {
-            /* make null brush check simpler... */
-            BRUSHOBJ_UnlockBrush(FillBrushObj);
-            FillBrushObj = NULL;
-        }
-        else
-        {
-            IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
-        }
+       INT tmp = Right; Right = Left; Left = tmp;
     }
-
-    PenBrushObj = PENOBJ_LockPen(dc->Dc_Attr.hpen);
-    if (PenBrushObj)
+    if (Bottom < Top)
     {
-        if (PenBrushObj->flAttrs & GDIBRUSH_IS_NULL)
-        {
-            /* make null pen check simpler... */
-            PENOBJ_UnlockPen(PenBrushObj);
-            PenBrushObj = NULL;
-        }
-        else
-        {
-            IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
-        }
+       INT tmp = Bottom; Bottom = Top; Top = tmp;
     }
 
-    right--;
-    bottom--;
-
-    width = right - left;
-    height = bottom - top;
-
-    if ( (xradius<<1) > width )
-        xradius = width >> 1;
-    if ( (yradius<<1) > height )
-        yradius = height >> 1;
-
-    b_square = yradius * yradius;
-    a_square = xradius * xradius;
-    row = yradius;
-    col = 0;
-    two_a_square = a_square << 1;
-    four_a_square = a_square << 2;
-    four_b_square = b_square << 2;
-    two_b_square = b_square << 1;
-    d = two_a_square * ((row - 1) * (row))
-        + a_square
-        + two_b_square * (1 - a_square);
-
-    x1 = left+xradius;
-    x2 = right-xradius;
-    y1 = top;
-    y2 = bottom;
-
-    x1start = x1;
-    x2start = x2;
-
-    dinc = two_b_square*3; /* two_b_square * (3 + (col << 1)); */
-    ddec = four_a_square * row;
-
-    first = TRUE;
-    for ( ;; )
-    {
-        if ( d >= 0 )
-        {
-            if ( FillBrushObj )
-                PUTLINE ( x1, y1, x2, y1, FillBrushInst );
-            if ( first )
-            {
-                if ( PenBrushObj )
-                {
-                    if ( x1start > x1 )
-                    {
-                        PUTLINE ( x1, y1, x1start, y1, PenBrushInst );
-                        PUTLINE ( x2start+1, y2, x2+1, y2, PenBrushInst );
-                    }
-                    else
-                    {
-                        PUTPIXEL ( x1, y1, PenBrushInst );
-                        PUTPIXEL ( x2, y2, PenBrushInst );
-                    }
-                }
-                first = FALSE;
-            }
-            else
-            {
-                if ( FillBrushObj )
-                    PUTLINE ( x1, y2, x2, y2, FillBrushInst );
-                if ( PenBrushObj )
-                {
-                    if ( x1start >= x1 )
-                    {
-                        PUTLINE ( x1, y1, x1start+1, y1, PenBrushInst );
-                        PUTLINE ( x2start, y2, x2+1, y2, PenBrushInst );
-                    }
-                    else
-                    {
-                        PUTPIXEL ( x1, y1, PenBrushInst );
-                        PUTPIXEL ( x2, y2, PenBrushInst );
-                    }
-                }
-            }
-            if ( PenBrushObj )
-            {
-                if ( x1start > x1 )
-                {
-                    PUTLINE ( x1, y2, x1start+1, y2, PenBrushInst );
-                    PUTLINE ( x2start, y1, x2+1, y1, PenBrushInst );
-                }
-                else
-                {
-                    PUTPIXEL ( x1, y2, PenBrushInst );
-                    PUTPIXEL ( x2, y1, PenBrushInst );
-                }
-            }
-            x1start = x1-1;
-            x2start = x2+1;
-            row--, y1++, y2--, ddec -= four_a_square;
-            d -= ddec;
-        }
-
-        potential_steps = ( a_square * row ) / b_square - col + 1;
-        while ( d < 0 && potential_steps-- )
-        {
-            d += dinc; /* two_b_square * (3 + (col << 1)); */
-            col++, x1--, x2++, dinc += four_b_square;
-        }
+    pdcattr = dc->pdcattr;
 
-        if ( a_square * row <= b_square * col )
-            break;
-    };
+    if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+        DC_vUpdateFillBrush(dc);
 
-    d = two_b_square * (col + 1) * col
-        + two_a_square * (row * (row - 2) + 1)
-        + (1 - two_a_square) * b_square;
-    dinc = ddec; /* four_b_square * col; */
-    ddec = two_a_square * ((row << 1) - 3);
+    if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+        DC_vUpdateLineBrush(dc);
 
-    while ( row )
+    pbrushLine = PEN_LockPen(pdcattr->hpen);
+    if (!pbrushLine)
     {
-        if ( FillBrushObj )
-        {
-            PUTLINE ( x1, y1, x2, y1, FillBrushInst );
-            PUTLINE ( x1, y2, x2, y2, FillBrushInst );
-        }
-        if ( PenBrushObj )
-        {
-            PUTPIXEL ( x2, y1, PenBrushInst );
-            PUTPIXEL ( x1, y2, PenBrushInst );
-            PUTPIXEL ( x2, y2, PenBrushInst );
-            PUTPIXEL ( x1, y1, PenBrushInst );
-        }
-
-        if ( d <= 0 )
-        {
-            col++, x1--, x2++, dinc += four_b_square;
-            d += dinc; //four_b_square * col;
-        }
-
-        row--, y1++, y2--, ddec -= four_a_square;
-        d -= ddec; //two_a_square * ((row << 1) - 3);
+        /* Nothing to do, as we don't have a bitmap */
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        return FALSE;
     }
 
-    if ( FillBrushObj )
-    {
-        PUTLINE ( left, y1, right, y1, FillBrushInst );
-        PUTLINE ( left, y2, right, y2, FillBrushInst );
-    }
-    if ( PenBrushObj )
+    PenOrigWidth = PenWidth = pbrushLine->ptPenWidth.x;
+    if (pbrushLine->ulPenStyle == PS_NULL) PenWidth = 0;
+
+    if (pbrushLine->ulPenStyle == PS_INSIDEFRAME)
     {
-        if ( x1 > (left+1) )
-        {
-            PUTLINE ( left, y1, x1, y1, PenBrushInst );
-            PUTLINE ( x2+1, y1, right, y1, PenBrushInst );
-            PUTLINE ( left+1, y2, x1, y2, PenBrushInst );
-            PUTLINE ( x2+1, y2, right+1, y2, PenBrushInst );
-        }
-        else
-        {
-            PUTPIXEL ( left, y1, PenBrushInst );
-            PUTPIXEL ( right, y2, PenBrushInst );
-        }
+       if (2*PenWidth > (Right - Left)) PenWidth = (Right -Left + 1)/2;
+       if (2*PenWidth > (Bottom - Top)) PenWidth = (Bottom -Top + 1)/2;
+       Left   += PenWidth / 2;
+       Right  -= (PenWidth - 1) / 2;
+       Top    += PenWidth / 2;
+       Bottom -= (PenWidth - 1) / 2;
     }
 
-    x1 = left+xradius;
-    x2 = right-xradius;
-    y1 = top+yradius;
-    y2 = bottom-yradius;
+    if (!PenWidth) PenWidth = 1;
+    pbrushLine->ptPenWidth.x = PenWidth;  
 
-    if ( FillBrushObj )
-    {
-        for ( i = y1+1; i < y2; i++ )
-            PUTLINE ( left, i, right, i, FillBrushInst );
-    }
+    RectBounds.left = Left;
+    RectBounds.top = Top;
+    RectBounds.right = Right;
+    RectBounds.bottom = Bottom;
 
-    if ( PenBrushObj )
-    {
-        PUTLINE ( x1,    top,    x2,    top,    PenBrushInst );
-        PUTLINE ( right, y1,     right, y2,     PenBrushInst );
-        PUTLINE ( x2,    bottom, x1,    bottom, PenBrushInst );
-        PUTLINE ( left,  y2,     left,  y1,     PenBrushInst );
-    }
+    IntLPtoDP(dc, (LPPOINT)&RectBounds, 2);
 
-    BITMAPOBJ_UnlockBitmap(BitmapObj);
-    if (PenBrushObj != NULL)
-        PENOBJ_UnlockPen(PenBrushObj);
-    if (FillBrushObj != NULL)
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
+    RectBounds.left   += dc->ptlDCOrig.x;
+    RectBounds.top    += dc->ptlDCOrig.y;
+    RectBounds.right  += dc->ptlDCOrig.x;
+    RectBounds.bottom += dc->ptlDCOrig.y;
 
+    pbrushFill = BRUSH_LockBrush(pdcattr->hbrush);
+    if (NULL == pbrushFill)   
+    {
+        DPRINT1("FillRound Fail\n");
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        ret = FALSE;
+    } 
+    else
+    {
+        RtlCopyMemory(&brushTemp, pbrushFill, sizeof(brushTemp));
+        brushTemp.ptOrigin.x += RectBounds.left - Left;
+        brushTemp.ptOrigin.y += RectBounds.top - Top;
+        ret = IntFillRoundRect( dc,
+                                RectBounds.left,
+                                RectBounds.top,
+                                RectBounds.right,
+                                RectBounds.bottom,
+                                xCurveDiameter,
+                                yCurveDiameter,
+                                &brushTemp);
+        BRUSH_UnlockBrush(pbrushFill);
+    }
+
+    if (ret)
+       ret = IntDrawRoundRect( dc,
+                  RectBounds.left,
+                   RectBounds.top,
+                 RectBounds.right,
+                RectBounds.bottom,
+                   xCurveDiameter,
+                   yCurveDiameter,
+                   pbrushLine);
+
+    pbrushLine->ptPenWidth.x = PenOrigWidth;
+    PEN_UnlockPen(pbrushLine);
     return ret;
 }
 
 BOOL
-STDCALL
+APIENTRY
 NtGdiRoundRect(
     HDC  hDC,
     int  LeftRect,
@@ -1442,7 +822,7 @@ NtGdiRoundRect(
         DPRINT1("NtGdiRoundRect() - hDC is invalid\n");
         SetLastWin32Error(ERROR_INVALID_HANDLE);
     }
-    else if (dc->IsIC)
+    else if (dc->dctype == DC_TYPE_INFO)
     {
         DC_UnlockDc(dc);
         /* Yes, Windows really returns TRUE in this case */
@@ -1457,39 +837,36 @@ NtGdiRoundRect(
     return ret;
 }
 
-BOOL FASTCALL
-IntGdiGradientFill(
-    DC *dc,
+BOOL
+NTAPI
+GreGradientFill(
+    HDC hdc,
     PTRIVERTEX pVertex,
-    ULONG uVertex,
+    ULONG nVertex,
     PVOID pMesh,
-    ULONG uMesh,
+    ULONG nMesh,
     ULONG ulMode)
 {
-    BITMAPOBJ *BitmapObj;
-    PPALGDI PalDestGDI;
-    XLATEOBJ *XlateObj;
-    RECTL Extent;
-    POINTL DitherOrg;
-    ULONG Mode, i;
-    BOOL Ret;
-
-    ASSERT(dc);
-    ASSERT(pVertex);
-    ASSERT(uVertex);
-    ASSERT(pMesh);
-    ASSERT(uMesh);
-
-    /* check parameters */
-    if (ulMode & GRADIENT_FILL_TRIANGLE)
-    {
-        PGRADIENT_TRIANGLE tr = (PGRADIENT_TRIANGLE)pMesh;
-
-        for (i = 0; i < uMesh; i++, tr++)
+    PDC pdc;
+    SURFACE *psurf;
+    PPALETTE ppal;
+    EXLATEOBJ exlo;
+    RECTL rclExtent;
+    POINTL ptlDitherOrg;
+    ULONG i;
+    BOOL bRet;
+    HPALETTE hDestPalette;
+
+    /* Check parameters */
+    if (ulMode == GRADIENT_FILL_TRIANGLE)
+    {
+        PGRADIENT_TRIANGLE pTriangle = (PGRADIENT_TRIANGLE)pMesh;
+
+        for (i = 0; i < nMesh; i++, pTriangle++)
         {
-            if (tr->Vertex1 >= uVertex ||
-                    tr->Vertex2 >= uVertex ||
-                    tr->Vertex3 >= uVertex)
+            if (pTriangle->Vertex1 >= nVertex ||
+                pTriangle->Vertex2 >= nVertex ||
+                pTriangle->Vertex3 >= nVertex)
             {
                 SetLastWin32Error(ERROR_INVALID_PARAMETER);
                 return FALSE;
@@ -1498,10 +875,10 @@ IntGdiGradientFill(
     }
     else
     {
-        PGRADIENT_RECT rc = (PGRADIENT_RECT)pMesh;
-        for (i = 0; i < uMesh; i++, rc++)
+        PGRADIENT_RECT pRect = (PGRADIENT_RECT)pMesh;
+        for (i = 0; i < nMesh; i++, pRect++)
         {
-            if (rc->UpperLeft >= uVertex || rc->LowerRight >= uVertex)
+            if (pRect->UpperLeft >= nVertex || pRect->LowerRight >= nVertex)
             {
                 SetLastWin32Error(ERROR_INVALID_PARAMETER);
                 return FALSE;
@@ -1509,86 +886,98 @@ IntGdiGradientFill(
         }
     }
 
+    /* Lock the output DC */
+    pdc = DC_LockDc(hdc);
+    if (!pdc)
+    {
+        SetLastWin32Error(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+
+    if (pdc->dctype == DC_TYPE_INFO)
+    {
+        DC_UnlockDc(pdc);
+        /* Yes, Windows really returns TRUE in this case */
+        return TRUE;
+    }
+
+    psurf = pdc->dclevel.pSurface;
+    if (!psurf)
+    {
+        /* Memory DC with no surface selected */
+        DC_UnlockDc(pdc);
+        return TRUE; // CHECKME
+    }
+
     /* calculate extent */
-    Extent.left = Extent.right = pVertex->x;
-    Extent.top = Extent.bottom = pVertex->y;
-    for (i = 0; i < uVertex; i++)
+    rclExtent.left = rclExtent.right = pVertex->x;
+    rclExtent.top = rclExtent.bottom = pVertex->y;
+    for (i = 0; i < nVertex; i++)
     {
-        Extent.left = min(Extent.left, (pVertex + i)->x);
-        Extent.right = max(Extent.right, (pVertex + i)->x);
-        Extent.top = min(Extent.top, (pVertex + i)->y);
-        Extent.bottom = max(Extent.bottom, (pVertex + i)->y);
+        rclExtent.left = min(rclExtent.left, (pVertex + i)->x);
+        rclExtent.right = max(rclExtent.right, (pVertex + i)->x);
+        rclExtent.top = min(rclExtent.top, (pVertex + i)->y);
+        rclExtent.bottom = max(rclExtent.bottom, (pVertex + i)->y);
     }
 
-    DitherOrg.x = dc->w.DCOrgX;
-    DitherOrg.y = dc->w.DCOrgY;
-    Extent.left += DitherOrg.x;
-    Extent.right += DitherOrg.x;
-    Extent.top += DitherOrg.y;
-    Extent.bottom += DitherOrg.y;
-
-    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
-    /* FIXME - BitmapObj can be NULL!!! Don't assert but handle this case gracefully! */
-    ASSERT(BitmapObj);
-
-    PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
-    /* FIXME - PalDestGDI can be NULL!!! Don't assert but handle this case gracefully! */
-    ASSERT(PalDestGDI);
-    Mode = PalDestGDI->Mode;
-    PALETTE_UnlockPalette(PalDestGDI);
-
-    XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
-    ASSERT(XlateObj);
-
-    Ret = IntEngGradientFill(&BitmapObj->SurfObj,
-                             dc->CombinedClip,
-                             XlateObj,
-                             pVertex,
-                             uVertex,
-                             pMesh,
-                             uMesh,
-                             &Extent,
-                             &DitherOrg,
-                             ulMode);
-
-    BITMAPOBJ_UnlockBitmap(BitmapObj);
-    EngDeleteXlate(XlateObj);
+    IntLPtoDP(pdc, (LPPOINT)&rclExtent, 2);
+    rclExtent.left   += pdc->ptlDCOrig.x;
+    rclExtent.right  += pdc->ptlDCOrig.x;
+    rclExtent.top    += pdc->ptlDCOrig.y;
+    rclExtent.bottom += pdc->ptlDCOrig.y;
 
-    return Ret;
+    ptlDitherOrg.x = ptlDitherOrg.y = 0;
+    IntLPtoDP(pdc, (LPPOINT)&ptlDitherOrg, 1);
+    ptlDitherOrg.x += pdc->ptlDCOrig.x;
+    ptlDitherOrg.y += pdc->ptlDCOrig.y;
+
+    hDestPalette = psurf->hDIBPalette;
+    if (!hDestPalette) hDestPalette = pPrimarySurface->devinfo.hpalDefault;
+
+    ppal = PALETTE_LockPalette(hDestPalette);
+    EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0, 0);
+
+    ASSERT(pdc->rosdc.CombinedClip);
+
+    bRet = IntEngGradientFill(&psurf->SurfObj,
+                              pdc->rosdc.CombinedClip,
+                              &exlo.xlo,
+                              pVertex,
+                              nVertex,
+                              pMesh,
+                              nMesh,
+                              &rclExtent,
+                              &ptlDitherOrg,
+                              ulMode);
+
+    EXLATEOBJ_vCleanup(&exlo);
+
+    if (ppal)
+        PALETTE_UnlockPalette(ppal);
+
+    DC_UnlockDc(pdc);
+
+    return bRet;
 }
 
 BOOL
-STDCALL
+APIENTRY
 NtGdiGradientFill(
     HDC hdc,
     PTRIVERTEX pVertex,
-    ULONG uVertex,
+    ULONG nVertex,
     PVOID pMesh,
-    ULONG uMesh,
+    ULONG nMesh,
     ULONG ulMode)
 {
-    DC *dc;
-    BOOL Ret;
+    BOOL bRet;
     PTRIVERTEX SafeVertex;
     PVOID SafeMesh;
-    ULONG SizeMesh;
-    NTSTATUS Status = STATUS_SUCCESS;
+    ULONG cbVertex, cbMesh;
 
-    dc = DC_LockDc(hdc);
-    if (!dc)
-    {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
-        return FALSE;
-    }
-    if (dc->IsIC)
-    {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
-    }
-    if (!pVertex || !uVertex || !pMesh || !uMesh)
+    /* Validate parameters */
+    if (!pVertex || !nVertex || !pMesh || !nMesh)
     {
-        DC_UnlockDc(dc);
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
@@ -1597,80 +986,58 @@ NtGdiGradientFill(
     {
         case GRADIENT_FILL_RECT_H:
         case GRADIENT_FILL_RECT_V:
-            SizeMesh = uMesh * sizeof(GRADIENT_RECT);
+            cbMesh = nMesh * sizeof(GRADIENT_RECT);
             break;
         case GRADIENT_FILL_TRIANGLE:
-            SizeMesh = uMesh * sizeof(TRIVERTEX);
+            cbMesh = nMesh * sizeof(GRADIENT_TRIANGLE);
             break;
         default:
-            DC_UnlockDc(dc);
             SetLastWin32Error(ERROR_INVALID_PARAMETER);
             return FALSE;
     }
 
-    _SEH_TRY
+    cbVertex = nVertex * sizeof(TRIVERTEX);
+    if (cbVertex + cbMesh <= cbVertex)
     {
-        ProbeForRead(pVertex,
-                     uVertex * sizeof(TRIVERTEX),
-                     1);
-        ProbeForRead(pMesh,
-                     SizeMesh,
-                     1);
-    }
-    _SEH_HANDLE
-    {
-        Status = _SEH_GetExceptionCode();
-    }
-    _SEH_END;
-
-    if (!NT_SUCCESS(Status))
-    {
-        DC_UnlockDc(dc);
-        SetLastWin32Error(Status);
+        /* Overflow */
         return FALSE;
     }
 
-    if (!(SafeVertex = ExAllocatePoolWithTag(PagedPool, (uVertex * sizeof(TRIVERTEX)) + SizeMesh, TAG_SHAPE)))
+    /* Allocate a kernel mode buffer */
+    SafeVertex = ExAllocatePoolWithTag(PagedPool, cbVertex + cbMesh, TAG_SHAPE);
+    if (!SafeVertex)
     {
-        DC_UnlockDc(dc);
         SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
         return FALSE;
     }
 
-    SafeMesh = (PTRIVERTEX)(SafeVertex + uVertex);
+    SafeMesh = (PVOID)((ULONG_PTR)SafeVertex + cbVertex);
 
-    _SEH_TRY
+    /* Copy the parameters to kernel mode */
+    _SEH2_TRY
     {
-        /* pointers were already probed! */
-        RtlCopyMemory(SafeVertex,
-                      pVertex,
-                      uVertex * sizeof(TRIVERTEX));
-        RtlCopyMemory(SafeMesh,
-                      pMesh,
-                      SizeMesh);
+        ProbeForRead(pVertex, cbVertex, 1);
+        ProbeForRead(pMesh, cbMesh, 1);
+        RtlCopyMemory(SafeVertex, pVertex, cbVertex);
+        RtlCopyMemory(SafeMesh, pMesh, cbMesh);
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
-        Status = _SEH_GetExceptionCode();
+        ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
+        SetLastNtError(_SEH2_GetExceptionCode());
+        _SEH2_YIELD(return FALSE;)
     }
-    _SEH_END;
+    _SEH2_END;
 
-    if (!NT_SUCCESS(Status))
-    {
-        DC_UnlockDc(dc);
-        ExFreePool(SafeVertex);
-        SetLastNtError(Status);
-        return FALSE;
-    }
-
-    Ret = IntGdiGradientFill(dc, SafeVertex, uVertex, SafeMesh, uMesh, ulMode);
+    /* Call the internal function */
+    bRet = GreGradientFill(hdc, SafeVertex, nVertex, SafeMesh, nMesh, ulMode);
 
-    DC_UnlockDc(dc);
-    ExFreePool(SafeVertex);
-    return Ret;
+    /* Cleanup and return result */
+    ExFreePoolWithTag(SafeVertex, TAG_SHAPE);
+    return bRet;
 }
 
-BOOL STDCALL
+BOOL APIENTRY
 NtGdiExtFloodFill(
     HDC  hDC,
     INT  XStart,
@@ -1678,10 +1045,74 @@ NtGdiExtFloodFill(
     COLORREF  Color,
     UINT  FillType)
 {
-    DPRINT1("FIXME: NtGdiExtFloodFill is UNIMPLEMENTED\n");
+    PDC dc;
+    PDC_ATTR   pdcattr;
+    SURFACE    *psurf = NULL;
+    HPALETTE   hpal;
+    PPALETTE   ppal;
+    EXLATEOBJ  exlo;
+    BOOL       Ret = FALSE;
+    RECTL      DestRect;
+    POINTL     Pt;
+    ULONG      ConvColor;
 
-    /* lie and say we succeded */
-    return TRUE;
+    dc = DC_LockDc(hDC);
+    if (!dc)
+    {
+        SetLastWin32Error(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
+    if (dc->dctype == DC_TYPE_INFO)
+    {
+        DC_UnlockDc(dc);
+        /* Yes, Windows really returns TRUE in this case */
+        return TRUE;
+    }
+
+    pdcattr = dc->pdcattr;
+
+    if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
+        DC_vUpdateFillBrush(dc);
+
+    if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
+        DC_vUpdateLineBrush(dc);
+
+    Pt.x = XStart;
+    Pt.y = YStart;
+    IntLPtoDP(dc, (LPPOINT)&Pt, 1);
+
+    Ret = NtGdiPtInRegion(dc->rosdc.hGCClipRgn, Pt.x, Pt.y);
+    if (Ret)
+        IntGdiGetRgnBox(dc->rosdc.hGCClipRgn,(LPRECT)&DestRect);
+    else
+        goto cleanup;
+
+    psurf = dc->dclevel.pSurface;
+    if (!psurf)
+    {
+        Ret = FALSE;
+        goto cleanup;
+    }
+
+    hpal = dc->dclevel.pSurface->hDIBPalette;
+    if (!hpal) hpal = pPrimarySurface->devinfo.hpalDefault;
+    ppal = PALETTE_ShareLockPalette(hpal);
+    
+    EXLATEOBJ_vInitialize(&exlo, &gpalRGB, ppal, 0, 0xffffff, 0);
+
+    /* Only solid fills supported for now
+     * How to support pattern brushes and non standard surfaces (not offering dib functions):
+     * Version a (most likely slow): call DrvPatBlt for every pixel
+     * Version b: create a flood mask and let MaskBlt blit a masked brush */
+    ConvColor = XLATEOBJ_iXlate(&exlo.xlo, Color);
+    Ret = DIB_XXBPP_FloodFillSolid(&psurf->SurfObj, &dc->eboFill.BrushObject, &DestRect, &Pt, ConvColor, FillType);
+
+    EXLATEOBJ_vCleanup(&exlo);
+    PALETTE_ShareUnlockPalette(ppal);
+
+cleanup:
+    DC_UnlockDc(dc);
+    return Ret;
 }
 
 /* EOF */