Path needed some love Phase I:
authorJames Tabor <james.tabor@reactos.org>
Fri, 27 Jun 2008 00:06:46 +0000 (00:06 +0000)
committerJames Tabor <james.tabor@reactos.org>
Fri, 27 Jun 2008 00:06:46 +0000 (00:06 +0000)
- Rewrite Path handle support and reordered path.c.
- Wine Sync/Port PATH_WidenPath and PATH_DoArcPart. Wine Path test results: 151 tests executed (0 marked as todo, 24 failures). 3 skipped.
- Found where the use of SelectObject in DC_InitDC, placed nulls into hbrush and hpen, I comment out and used StockObject and now default drawing works.
- Implemented AngleArc and most of Arc. This is very experimental and it does draw and does not crash.
- Cleaned up some files with extra <CR> at the end of lines.
- Fully tested: Taskmgr, FF 1.5, Abiword, drawing programs, and all.
- Note: Path drawing is majorly misaligned. Fill path will draw in one area and Stroke path will draw in another.
- Note: Trunk: Gdi wine DC test: dc.c:89 Failed to lock hDC, sometimes locking up the system. See bug 3333.

svn path=/trunk/; revision=34119

reactos/subsystems/win32/win32k/include/dc.h
reactos/subsystems/win32/win32k/include/path.h
reactos/subsystems/win32/win32k/objects/arc.c
reactos/subsystems/win32/win32k/objects/bitblt.c
reactos/subsystems/win32/win32k/objects/dc.c
reactos/subsystems/win32/win32k/objects/fillshap.c
reactos/subsystems/win32/win32k/objects/line.c
reactos/subsystems/win32/win32k/objects/path.c
reactos/subsystems/win32/win32k/objects/region.c

index f77011f..94ccbd3 100644 (file)
@@ -9,11 +9,6 @@
 // Get/SetBounds/Rect support.
 #define DCB_WINDOWMGR 0x8000 // Queries the Windows bounding rectangle instead of the application's
 
-  /* DCPATH flPath */
-#define DCPATH_ACTIVE    0x0001
-#define DCPATH_SAVE      0x0002
-#define DCPATH_CLOCKWISE 0x0004
-
 // GDIDEVICE flags
 #define PDEV_DISPLAY             0x00000001 // Display device
 #define PDEV_HARDWARE_POINTER    0x00000002 // Supports hardware cursor
 
 /* Type definitions ***********************************************************/
 
-typedef enum tagGdiPathState
-{
-   PATH_Null,
-   PATH_Open,
-   PATH_Closed
-} GdiPathState;
-
-typedef struct tagGdiPath
-{
-   GdiPathState state;
-   POINT        *pPoints;
-   BYTE         *pFlags;
-   int          numEntriesUsed, numEntriesAllocated;
-   BOOL         newStroke;
-} GdiPath;
-
 typedef struct _WIN_DC_INFO
 {
   HRGN     hClipRgn;     /* Clip region (may be 0) */
@@ -60,10 +39,6 @@ typedef struct _WIN_DC_INFO
   HRGN     hGCClipRgn;   /* GC clip region (ClipRgn AND VisRgn) */
   HBITMAP  hBitmap;
 
-/* #if 0 */
-    GdiPath       path;
-/* #endif */
-
   BYTE   bitsPerPixel;
 } WIN_DC_INFO;
 
index 62761d6..d7e2117 100644 (file)
@@ -1,6 +1,22 @@
 #ifndef _WIN32K_PATH_H
 #define _WIN32K_PATH_H
 
+  /* DCPATH flPath */
+#define DCPATH_ACTIVE    0x0001
+#define DCPATH_SAVE      0x0002
+#define DCPATH_CLOCKWISE 0x0004
+// ReactOS only
+#define DCPATH_SAVESTATE 0x80000000
+
+typedef HGDIOBJ HPATH, *PHPATH;
+
+typedef enum tagGdiPathState
+{
+   PATH_Null,
+   PATH_Open,
+   PATH_Closed
+} GdiPathState;
+
 typedef struct _PATH
 {
   BASEOBJECT   BaseObject;
@@ -26,19 +42,19 @@ typedef struct _EPATHOBJ
 #define  PATH_AllocPath() ((PPATH) GDIOBJ_AllocObj(GDIObjType_PATH_TYPE))
 #define  PATH_AllocPathWithHandle() ((PPATH) GDIOBJ_AllocObjWithHandle (GDI_OBJECT_TYPE_PATH))
 #define  PATH_FreePath(pPath)  GDIOBJ_FreeObj((POBJ)pPath, GDIObjType_PATH_TYPE)
-#define  PATH_FreePathByHandle(hPath)  GDIOBJ_FreeObjbyHandle((HGDIOBJ)hPath, GDI_OBJECT_TYPE_PATH)
-#define  PATH_LockPath(hPath) ((PROSRGNDATA)GDIOBJ_LockObj((HGDIOBJ)hPath, GDI_OBJECT_TYPE_PATH))
-#define  PATH_UnlockPath(pPath) GDIOBJ_UnlockObjByPtr((POBJ)pPath)
+#define  PATH_FreeExtPathByHandle(hPath) GDIOBJ_FreeObjByHandle((HGDIOBJ) hPath, GDI_OBJECT_TYPE_PATH)
+#define  PATH_LockPath(hPath) ((PPATH)GDIOBJ_ShareLockObj((HGDIOBJ)hPath, GDI_OBJECT_TYPE_PATH))
+#define  PATH_UnlockPath(pPath) GDIOBJ_ShareUnlockObjByPtr((POBJ)pPath)
 
 
-#define PATH_IsPathOpen(path) ((path).state==PATH_Open)
+#define PATH_IsPathOpen(DcLevel) ( ((DcLevel).hPath) && ((DcLevel).flPath & DCPATH_ACTIVE) )
 
 BOOL FASTCALL PATH_Arc (PDC dc, INT x1, INT y1, INT x2, INT y2, INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines);
-BOOL FASTCALL PATH_AssignGdiPath (GdiPath *pPathDest, const GdiPath *pPathSrc);
-VOID FASTCALL PATH_DestroyGdiPath (GdiPath *pPath);
+BOOL FASTCALL PATH_AssignGdiPath (PPATH pPathDest, const PPATH pPathSrc);
+VOID FASTCALL PATH_DestroyGdiPath (PPATH pPath);
 BOOL FASTCALL PATH_Ellipse (PDC dc, INT x1, INT y1, INT x2, INT y2);
-VOID FASTCALL PATH_EmptyPath (GdiPath *pPath);
-VOID FASTCALL PATH_InitGdiPath (GdiPath *pPath);
+VOID FASTCALL PATH_EmptyPath (PPATH pPath);
+VOID FASTCALL PATH_InitGdiPath (PPATH pPath);
 BOOL FASTCALL PATH_LineTo (PDC dc, INT x, INT y);
 BOOL FASTCALL PATH_MoveTo (PDC dc);
 BOOL FASTCALL PATH_PolyBezier (PDC dc, const POINT *pts, DWORD cbPoints);
@@ -50,8 +66,9 @@ BOOL FASTCALL PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UI
 BOOL FASTCALL PATH_PolyPolyline( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines);
 BOOL FASTCALL PATH_Rectangle (PDC dc, INT x1, INT y1, INT x2, INT y2);
 BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height);
-BOOL FASTCALL PATH_PathToRegion (GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn);
+BOOL FASTCALL PATH_PathToRegion (PPATH pPath, INT nPolyFillMode, HRGN *pHrgn);
 
-VOID FASTCALL IntGdiCloseFigure(PDC pDc);
+VOID FASTCALL IntGdiCloseFigure(PPATH pPath);
+BOOL FASTCALL PATH_Delete(HPATH hPath);
 
 #endif /* _WIN32K_PATH_H */
index 696691f..28b6c57 100644 (file)
-\r
-#include <w32k.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-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)
-\r
-#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 (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);
-    }
-
-    while (X < Y)
-    {
-        if (d < 0)
-        {
-            d += (X << 1) + (Even ? 4 : 3);
-
-            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);
-    }
-}
-
-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;
-
-    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;
-    }
-
-    if (deltay < 0)
-    {
-        ychange = -1;
-        deltay = - deltay;
-        y--;
-        Type = (Start ? SHAPEPOINT_TYPE_LINE_LEFT : SHAPEPOINT_TYPE_LINE_RIGHT);
-    }
-    else
-    {
-        ychange = 1;
-        Type = (Start ? SHAPEPOINT_TYPE_LINE_RIGHT : SHAPEPOINT_TYPE_LINE_LEFT);
-    }
 
-    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
-    {
-        error = 0;
-
-        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
-        {
-            for (i = 0; i < deltax; i++)
-            {
-                SETPOINT(x, y, Type);
-                x = x + xchange;
-                error = error + deltay;
-                if (deltax <= error)
-                {
-                    y = y + ychange;
-                    error = error - deltax;
-                }
-            }
-        }
-    }
-}
-
-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)
-    {
-        return +1;
-    }
-    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
-
-\r
+#include <w32k.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_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_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)))
+
+static
 BOOL
-STDCALL
-NtGdiPie(HDC  hDC,
-         int  Left,
-         int  Top,
-         int  Right,
-         int  Bottom,
-         int  XRadialStart,
-         int  YRadialStart,
-         int  XRadialEnd,
-         int  YRadialEnd)
+FASTCALL
+IntArc( DC *dc, 
+        int  Left,
+        int  Top,
+        int  Right,
+        int  Bottom,
+        int  XRadialStart,
+        int  YRadialStart,
+        int  XRadialEnd,
+        int  YRadialEnd,
+        ARCTYPE arctype)
 {
-#ifdef TODO
-    PDC dc;
-    PDC_ATTR;
+    PDC_ATTR Dc_Attr;
     RECTL RectBounds;
-    SURFOBJ *SurfObj;
-    BRUSHOBJ PenBrushObj;
-    PBRUSHOBJ FillBrushObj;
-    PSHAPEPOINT ShapePoints;
-    UINT Point, PointCount;
+    PGDIBRUSHOBJ PenBrushObj, FillBrushObj;
+    GDIBRUSHINST FillBrushInst, PenBrushInst;
+    BITMAPOBJ *BitmapObj;
     BOOL ret = TRUE;
-    int Y, CircleStart, CircleEnd, LineStart, LineEnd;
-    BOOL FullFill;
-
-    if (Right <= Left || Bottom <= Top)
+    double AngleStart, AngleEnd;
+    LONG RadiusX, RadiusY, CenterX, CenterY;
+    LONG SfCx, SfCy, EfCx, EfCy;
+
+/*                  top
+            ___________________
+          +|                   |
+           |                   |
+           |                   |
+      left |                   | right
+           |                   |
+           |                   |
+          0|___________________|
+            0     bottom       +
+ */
+    if (Right <= Left || Top <= Bottom)
     {
+        DPRINT1("Arc Fail 1\n");
         SetLastWin32Error(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
-
+/*
     if (Right - Left != Bottom - Top)
     {
         UNIMPLEMENTED;
     }
+*/
+    Dc_Attr = dc->pDc_Attr;
+    if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-    dc = DC_LockDc ( hDC );
-    if (NULL == dc)
+    FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+    if (NULL == FillBrushObj)
     {
-        SetLastWin32Error(ERROR_INVALID_HANDLE);
+        DPRINT1("Arc Fail 2\n");
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
         return FALSE;
     }
-    if (dc->DC_Type == DC_TYPE_INFO)
+
+    PenBrushObj = PENOBJ_LockPen(Dc_Attr->hpen);
+    if (NULL == PenBrushObj)
     {
-        DC_UnlockDc(dc);
-        /* Yes, Windows really returns TRUE in this case */
-        return TRUE;
+        DPRINT1("Arc Fail 3\n");
+        BRUSHOBJ_UnlockBrush(FillBrushObj);
+        SetLastWin32Error(ERROR_INTERNAL_ERROR);
+        return FALSE;
     }
 
-    Dc_Attr = dc->pDc_Attr;
-    if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-
-    FillBrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
-    if (NULL == FillBrushObj)
+    BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+    if (NULL == BitmapObj)
     {
-        DC_UnlockDc(dc);
+        DPRINT1("Arc Fail 4\n");
+        BRUSHOBJ_UnlockBrush(FillBrushObj);
+        PENOBJ_UnlockPen(PenBrushObj);
         SetLastWin32Error(ERROR_INTERNAL_ERROR);
         return FALSE;
     }
 
-    Left += dc->ptlDCOrig.x;
-    Right += dc->ptlDCOrig.x;
-    Top += dc->ptlDCOrig.y;
+    IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
+    IntGdiInitBrushInstance(&PenBrushInst, PenBrushObj, dc->XlatePen);
+
+    Left   += dc->ptlDCOrig.x;
+    Right  += dc->ptlDCOrig.x;
+    Top    += dc->ptlDCOrig.y;
     Bottom += dc->ptlDCOrig.y;
+
     XRadialStart += dc->ptlDCOrig.x;
     YRadialStart += dc->ptlDCOrig.y;
-    XRadialEnd += dc->ptlDCOrig.x;
-    YRadialEnd += dc->ptlDCOrig.y;
+    XRadialEnd   += dc->ptlDCOrig.x;
+    YRadialEnd   += dc->ptlDCOrig.y;
 
-    RectBounds.left = Left;
-    RectBounds.right = Right;
-    RectBounds.top = Top;
-    RectBounds.bottom = Bottom;
+    DPRINT1("1: StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
+               XRadialStart,YRadialStart,XRadialEnd,YRadialEnd);
 
-    SurfObj = (SURFOBJ*) AccessUserObject((ULONG)dc->Surface);
-    HPenToBrushObj(&PenBrushObj, 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)
-    {
-        BRUSHOBJ_UnlockBrush(FillBrushObj);
-        DC_UnlockDc(dc);
-
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        return FALSE;
-    }
+    RectBounds.left   = Left;
+    RectBounds.right  = Right;
+    RectBounds.top    = Top;
+    RectBounds.bottom = Bottom;
+    DPRINT1("1: Left: %d, Top: %d, Right: %d, Bottom: %d\n",
+               RectBounds.left,RectBounds.top,RectBounds.right,RectBounds.bottom);
 
     if (Left == Right)
     {
-        PUTPIXEL(Left, Top, &PenBrushObj);
+        DPRINT1("Arc Good Exit\n");
+        PUTPIXEL(Left, Top, PenBrushInst);
+        BITMAPOBJ_UnlockBitmap(BitmapObj);
         BRUSHOBJ_UnlockBrush(FillBrushObj);
-        DC_UnlockDc(dc);
-
+        PENOBJ_UnlockPen(PenBrushObj);
         return ret;
     }
+    RadiusX = (RectBounds.right - RectBounds.left)/2;
+    RadiusY = (RectBounds.bottom - RectBounds.top)/2;
+    CenterX = RectBounds.left + RadiusX;
+    CenterY = RectBounds.top + RadiusY;
+
+    AngleEnd   = atan2(-(YRadialEnd - CenterY), XRadialEnd - CenterX)* (180.0 / M_PI);
+    AngleStart = atan2(-(YRadialStart - CenterY), XRadialStart - CenterX)* (180.0 / M_PI);
 
-    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)
+    SfCx = (Rcos(AngleStart) * RadiusX);
+    SfCy = (Rsin(AngleStart) * RadiusY);
+
+    EfCx = (Rcos(AngleEnd) * RadiusX);
+    EfCy = (Rsin(AngleEnd) * RadiusY);
     {
-        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++;
-        }
-    }
+       FLOAT AngS = AngleStart, Factor = 1;
+       int x,y, ox = 0, oy = 0;
+
+       if (arctype == GdiTypePie)
+       {
+          PUTLINE(SfCx + CenterX, SfCy + CenterY, CenterX, CenterY, PenBrushInst);
+       }
+
+       for(; AngS < AngleEnd; AngS += Factor)
+       {
+          x = (Rcos(AngS) * RadiusX);
+          y = (Rsin(AngS) * RadiusY);
+  
+          if (arctype == GdiTypePie)
+             PUTLINE((x + CenterX) - 1, (y + CenterY) - 1, CenterX, CenterY, FillBrushInst);
+
+          PUTPIXEL (x + CenterX, y + CenterY, PenBrushInst);
+          ox = x;
+          oy = y;
+       }
+
+       if (arctype == GdiTypePie)
+           PUTLINE(EfCx + CenterX, EfCy + CenterY, CenterX, CenterY, PenBrushInst);
 
-    ExFreePool(ShapePoints);
+    }
+    BITMAPOBJ_UnlockBitmap(BitmapObj);
     BRUSHOBJ_UnlockBrush(FillBrushObj);
-    DC_UnlockDc(dc);
-
+    PENOBJ_UnlockPen(PenBrushObj);
+    DPRINT1("IntArc Exit.\n");
     return ret;
-#else
-    return TRUE;
-#endif
 }
-\r
-\r
-static BOOL FASTCALL\r
-IntArc( DC *dc, int LeftRect, int TopRect, int RightRect, int BottomRect,\r
-        int XStartArc, int YStartArc, int XEndArc, int YEndArc, ARCTYPE arctype)\r
-{\r
-  return TRUE;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntGdiArcInternal(\r
-          ARCTYPE arctype,\r
-          DC  *dc,\r
-          int LeftRect,\r
-          int TopRect,\r
-          int RightRect,\r
-          int BottomRect,\r
-          int XStartArc,\r
-          int YStartArc,\r
-          int XEndArc,\r
-          int YEndArc)\r
-{\r
-  INT rx, ry;\r
-  RECT rc, rc1;\r
-\r
-  if(PATH_IsPathOpen(dc->w.path))\r
-  {\r
-    INT type = arctype;\r
-    if (arctype == GdiTypeArcTo) type = GdiTypeArc;\r
-    return PATH_Arc(dc, LeftRect, TopRect, RightRect, BottomRect,\r
-                    XStartArc, YStartArc, XEndArc, YEndArc, type);\r
-  }\r
-\r
-  IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);\r
-  IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);\r
-\r
-  rx = (rc.right - rc.left)/2 - 1;\r
-  ry = (rc.bottom - rc.top)/2 -1;\r
-  rc.left += rx;\r
-  rc.top += ry;\r
-\r
-  return  IntArc( dc, rc.left, rc.top, rx, ry,\r
-          rc1.left, rc1.top, rc1.right, rc1.bottom, arctype);\r
-}\r
-\r
+
+
+BOOL FASTCALL
+IntGdiArcInternal(
+          ARCTYPE arctype,
+          DC  *dc,
+          int LeftRect,
+          int TopRect,
+          int RightRect,
+          int BottomRect,
+          int XStartArc,
+          int YStartArc,
+          int XEndArc,
+          int YEndArc)
+{
+  BOOL Ret;
+  RECT rc, rc1;
+  double AngleStart, AngleEnd;
+  LONG RadiusX, RadiusY, CenterX, CenterY, Width, Height;
+  LONG SfCx, SfCy, EfCx = 0, EfCy = 0;
+
+  DPRINT1("StartX: %d, StartY: %d, EndX: %d, EndY: %d\n",
+           XStartArc,YStartArc,XEndArc,YEndArc);
+  DPRINT1("Left: %d, Top: %d, Right: %d, Bottom: %d\n",
+           LeftRect,TopRect,RightRect,BottomRect);
+
+  if (PATH_IsPathOpen(dc->DcLevel))
+  {
+     return PATH_Arc( dc,
+                LeftRect,
+                 TopRect,
+               RightRect,
+              BottomRect,
+               XStartArc,
+               YStartArc,
+                 XEndArc,
+                 YEndArc,
+                 arctype);
+  }
+
+  if (arctype == GdiTypeArcTo)
+  {
+    Width   = fabs(RightRect - LeftRect);
+    Height  = fabs(BottomRect - TopRect);
+    RadiusX = Width/2;
+    RadiusY = Height/2;
+    CenterX = RightRect > LeftRect ? LeftRect + RadiusX : RightRect + RadiusX;
+    CenterY = BottomRect > TopRect ? TopRect + RadiusY : BottomRect + RadiusY;
+
+    AngleStart = atan2((YStartArc - CenterY)/Height, (XStartArc - CenterX)/Width);
+    AngleEnd   = atan2((YEndArc - CenterY)/Height, (XEndArc - CenterX)/Width);
+
+    EfCx = GDI_ROUND(CenterX+cos(AngleEnd) * RadiusX);
+    EfCy = GDI_ROUND(CenterY+sin(AngleEnd) * RadiusY);
+    SfCx = GDI_ROUND(CenterX+cos(AngleStart) * RadiusX);
+    SfCy = GDI_ROUND(CenterY+sin(AngleStart) * RadiusY);
+
+    IntGdiLineTo(dc, SfCx, SfCy);
+  }
+
+  IntGdiSetRect(&rc, LeftRect, TopRect, RightRect, BottomRect);
+  IntGdiSetRect(&rc1, XStartArc, YStartArc, XEndArc, YEndArc);
+
+//  IntLPtoDP(dc, (LPPOINT)&rc, 2);
+//  IntLPtoDP(dc, (LPPOINT)&rc1, 2);
+
+  Ret = IntArc( dc,
+           rc.left,
+            rc.top,
+          rc.right,
+         rc.bottom,
+          rc1.left,
+           rc1.top,
+         rc1.right,
+        rc1.bottom,
+           arctype);
+
+  if (arctype == GdiTypeArcTo)
+  {
+     dc->ptlDCOrig.x = EfCx;
+     dc->ptlDCOrig.y = EfCy;
+  }
+
+  return Ret;
+}
+
+BOOL
+FASTCALL
+IntGdiAngleArc( PDC pDC,
+                  INT x,
+                  INT y,
+         DWORD dwRadius,
+      FLOAT eStartAngle,
+      FLOAT eSweepAngle)
+{
+  INT  x1, y1, x2, y2, arcdir;
+  BOOL result;
+
+  /* Calculate the end point */
+  x2 = x + (INT)(cos(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
+  y2 = y - (INT)(sin(((eStartAngle+eSweepAngle)/360)*(M_PI*2)) * dwRadius);
+
+  x1 = x + (INT)(cos((eStartAngle/360)*(M_PI*2)) * dwRadius);
+  y1 = y - (INT)(sin((eStartAngle/360)*(M_PI*2)) * dwRadius);
+
+  arcdir = pDC->DcLevel.flPath & DCPATH_CLOCKWISE;
+  if (eSweepAngle >= 0)
+     pDC->DcLevel.flPath &= ~DCPATH_CLOCKWISE;
+  else
+     pDC->DcLevel.flPath |= DCPATH_CLOCKWISE;
+
+  result = IntGdiArcInternal( GdiTypeArcTo,
+                                       pDC,
+                                x-dwRadius,
+                                y+dwRadius,
+                                x+dwRadius,
+                                y-dwRadius,
+                                        x1,
+                                        y1,
+                                        x2,
+                                        y2 );
+
+  pDC->DcLevel.flPath |= (arcdir & DCPATH_CLOCKWISE);
+
+  if (result)
+  {
+     POINT point;
+     point.x=x2;
+     point.y=y2;
+//     CoordLPtoDP ( pDC, &point );
+     pDC->ptlDCOrig.x = point.x;
+     pDC->ptlDCOrig.y = point.y;
+  }
+  return result;
+}
+
+/* FUNCTIONS *****************************************************************/
+
 BOOL
 APIENTRY
 NtGdiAngleArc(
@@ -476,89 +328,72 @@ NtGdiAngleArc(
     IN DWORD dwStartAngle,
     IN DWORD dwSweepAngle)
 {
-  DC *dc;\r
-  BOOL Ret = FALSE;\r
-  gxf_long worker, worker1;\r
-\r
-  dc = DC_LockDc (hDC);\r
-  if(!dc)\r
-  {\r
-    SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-    return FALSE;\r
-  }\r
-  if (dc->DC_Type == DC_TYPE_INFO)\r
-  {\r
-    DC_UnlockDc(dc);\r
-    /* Yes, Windows really returns TRUE in this case */\r
-    return TRUE;\r
-  }\r
-  worker.l  = dwStartAngle;\r
-  worker1.l = dwSweepAngle;\r
-\r
-  DC_UnlockDc( dc );\r
-  return Ret;\r
+  DC *pDC;
+  BOOL Ret = FALSE;
+  gxf_long worker, worker1;
+
+  pDC = DC_LockDc (hDC);
+  if(!pDC)
+  {
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+  if (pDC->DC_Type == DC_TYPE_INFO)
+  {
+    DC_UnlockDc(pDC);
+    /* Yes, Windows really returns TRUE in this case */
+    return TRUE;
+  }
+  worker.l  = dwStartAngle;
+  worker1.l = dwSweepAngle;
+  Ret = IntGdiAngleArc( pDC, x, y, dwRadius, worker.f, worker1.f);
+  DC_UnlockDc( pDC );
+  return Ret;
 }
-\r
-BOOL\r
-STDCALL\r
-NtGdiArcInternal(\r
-        ARCTYPE arctype,\r
-        HDC  hDC,\r
-        int  LeftRect,\r
-        int  TopRect,\r
-        int  RightRect,\r
-        int  BottomRect,\r
-        int  XStartArc,\r
-        int  YStartArc,\r
-        int  XEndArc,\r
-        int  YEndArc)\r
-{\r
-  DC *dc;\r
-  BOOL Ret;\r
-\r
-  dc = DC_LockDc (hDC);\r
-  if(!dc)\r
-  {\r
-    SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-    return FALSE;\r
-  }\r
-  if (dc->DC_Type == DC_TYPE_INFO)\r
-  {\r
-    DC_UnlockDc(dc);\r
-    /* Yes, Windows really returns TRUE in this case */\r
-    return TRUE;\r
-  }\r
-\r
-  if (arctype == GdiTypeArcTo)\r
-  {\r
-    // Line from current position to starting point of arc\r
-    if ( !IntGdiLineTo(dc, XStartArc, YStartArc) )\r
-    {\r
-      DC_UnlockDc(dc);\r
-      return FALSE;\r
-    }\r
-  }\r
-\r
-  Ret = IntGdiArcInternal(\r
-                  arctype,\r
-                  dc,\r
-                  LeftRect,\r
-                  TopRect,\r
-                  RightRect,\r
-                  BottomRect,\r
-                  XStartArc,\r
-                  YStartArc,\r
-                  XEndArc,\r
-                  YEndArc);\r
-\r
-  if (arctype == GdiTypeArcTo)\r
-  {\r
-    // If no error occured, the current position is moved to the ending point of the arc.\r
-    if(Ret)\r
-      IntGdiMoveToEx(dc, XEndArc, YEndArc, NULL);\r
-  }\r
-\r
-  DC_UnlockDc( dc );\r
-  return Ret;\r
-}\r
-\r
+
+BOOL
+STDCALL
+NtGdiArcInternal(
+        ARCTYPE arctype,
+        HDC  hDC,
+        int  LeftRect,
+        int  TopRect,
+        int  RightRect,
+        int  BottomRect,
+        int  XStartArc,
+        int  YStartArc,
+        int  XEndArc,
+        int  YEndArc)
+{
+  DC *dc;
+  BOOL Ret;
+
+  dc = DC_LockDc (hDC);
+  if(!dc)
+  {
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+  if (dc->DC_Type == DC_TYPE_INFO)
+  {
+    DC_UnlockDc(dc);
+    /* Yes, Windows really returns TRUE in this case */
+    return TRUE;
+  }
+
+  Ret = IntGdiArcInternal(
+                  arctype,
+                  dc,
+                  LeftRect,
+                  TopRect,
+                  RightRect,
+                  BottomRect,
+                  XStartArc,
+                  YStartArc,
+                  XEndArc,
+                  YEndArc);
+
+  DC_UnlockDc( dc );
+  return Ret;
+}
+
index 459e3a2..b314033 100644 (file)
-/*\r
- *  ReactOS W32 Subsystem\r
- *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team\r
- *\r
- *  This program is free software; you can redistribute it and/or modify\r
- *  it under the terms of the GNU General Public License as published by\r
- *  the Free Software Foundation; either version 2 of the License, or\r
- *  (at your option) any later version.\r
- *\r
- *  This program is distributed in the hope that it will be useful,\r
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- *  GNU General Public License for more details.\r
- *\r
- *  You should have received a copy of the GNU General Public License\r
- *  along with this program; if not, write to the Free Software\r
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
- */\r
-/* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */\r
-\r
-#include <w32k.h>\r
-\r
-#define NDEBUG\r
-#include <debug.h>\r
-\r
-\r
-\r
-BOOL STDCALL\r
-NtGdiAlphaBlend(\r
-       HDC  hDCDest,\r
-       LONG  XOriginDest,\r
-       LONG  YOriginDest,\r
-       LONG  WidthDest,\r
-       LONG  HeightDest,\r
-       HDC  hDCSrc,\r
-       LONG  XOriginSrc,\r
-       LONG  YOriginSrc,\r
-       LONG  WidthSrc,\r
-       LONG  HeightSrc,\r
-       BLENDFUNCTION  BlendFunc,\r
-       HANDLE hcmXform)\r
-{\r
-       PDC DCDest = NULL;\r
-       PDC DCSrc  = NULL;\r
-       BITMAPOBJ *BitmapDest, *BitmapSrc;\r
-       RECTL DestRect, SourceRect;\r
-       BOOL Status;\r
-       XLATEOBJ *XlateObj;\r
-       BLENDOBJ BlendObj;\r
-       BlendObj.BlendFunction = BlendFunc;\r
-\r
-       DCDest = DC_LockDc(hDCDest);\r
-       if (NULL == DCDest)\r
-       {\r
-               DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCDest);\r
-               SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-               return FALSE;\r
-       }\r
-       if (DCDest->DC_Type == DC_TYPE_INFO)\r
-       {\r
-               DC_UnlockDc(DCDest);\r
-               /* Yes, Windows really returns TRUE in this case */\r
-               return TRUE;\r
-       }\r
-\r
-       if (hDCSrc != hDCDest)\r
-       {\r
-               DCSrc = DC_LockDc(hDCSrc);\r
-               if (NULL == DCSrc)\r
-               {\r
-                       DC_UnlockDc(DCDest);\r
-                       DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCSrc);\r
-                       SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-                       return FALSE;\r
-               }\r
-               if (DCSrc->DC_Type == DC_TYPE_INFO)\r
-               {\r
-                       DC_UnlockDc(DCSrc);\r
-                       DC_UnlockDc(DCDest);\r
-                       /* Yes, Windows really returns TRUE in this case */\r
-                       return TRUE;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               DCSrc = DCDest;\r
-       }\r
-\r
-       /* Offset the destination and source by the origin of their DCs. */\r
-       XOriginDest += DCDest->ptlDCOrig.x;\r
-       YOriginDest += DCDest->ptlDCOrig.y;\r
-       XOriginSrc += DCSrc->ptlDCOrig.x;\r
-       YOriginSrc += DCSrc->ptlDCOrig.y;\r
-\r
-       DestRect.left   = XOriginDest;\r
-       DestRect.top    = YOriginDest;\r
-       DestRect.right  = XOriginDest + WidthDest;\r
-       DestRect.bottom = YOriginDest + HeightDest;\r
-\r
-       SourceRect.left   = XOriginSrc;\r
-       SourceRect.top    = YOriginSrc;\r
-       SourceRect.right  = XOriginSrc + WidthSrc;\r
-       SourceRect.bottom = YOriginSrc + HeightSrc;\r
-\r
-       /* Determine surfaces to be used in the bitblt */\r
-       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
-       if (!BitmapDest)\r
-       {\r
-               DC_UnlockDc(DCSrc);\r
-               DC_UnlockDc(DCDest);\r
-               return FALSE;\r
-       }\r
-       if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
-               BitmapSrc = BitmapDest;\r
-       else\r
-       {\r
-               BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
-               if (!BitmapDest)\r
-               {\r
-                       BITMAPOBJ_UnlockBitmap(BitmapDest);\r
-                       DC_UnlockDc(DCSrc);\r
-                       DC_UnlockDc(DCDest);\r
-                       return FALSE;\r
-               }\r
-       }\r
-\r
-       /* Create the XLATEOBJ. */\r
-       XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
-\r
-       if (XlateObj == (XLATEOBJ*)-1)\r
-       {\r
-               DPRINT1("error!!!\n");\r
-               SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
-               XlateObj = NULL;\r
-               Status = FALSE;\r
-       }\r
-       else\r
-       {\r
-               /* Perform the alpha blend operation */\r
-               Status = IntEngAlphaBlend(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
-                                         DCDest->CombinedClip, XlateObj,\r
-                                         &DestRect, &SourceRect, &BlendObj);\r
-       }\r
-\r
-       if (XlateObj != NULL)\r
-               EngDeleteXlate(XlateObj);\r
-\r
-       BITMAPOBJ_UnlockBitmap(BitmapDest);\r
-       if (BitmapSrc != BitmapDest)\r
-               BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
-       DC_UnlockDc(DCDest);\r
-       if (hDCSrc != hDCDest)\r
-               DC_UnlockDc(DCSrc);\r
-\r
-       return Status;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiBitBlt(\r
-       HDC  hDCDest,\r
-       INT  XDest,\r
-       INT  YDest,\r
-       INT  Width,\r
-       INT  Height,\r
-       HDC  hDCSrc,\r
-       INT  XSrc,\r
-       INT  YSrc,\r
-       DWORD  ROP,\r
-       IN DWORD crBackColor,\r
-       IN FLONG fl)\r
-{\r
-       PDC DCDest = NULL;\r
-       PDC DCSrc  = NULL;\r
-       PDC_ATTR Dc_Attr = NULL;\r
-       BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;\r
-       RECTL DestRect;\r
-       POINTL SourcePoint, BrushOrigin;\r
-       BOOL Status = FALSE;\r
-       XLATEOBJ *XlateObj = NULL;\r
-       PGDIBRUSHOBJ BrushObj = NULL;\r
-       GDIBRUSHINST BrushInst;\r
-       BOOL UsesSource = ROP3_USES_SOURCE(ROP);\r
-       BOOL UsesPattern = ROP3_USES_PATTERN(ROP);\r
-\r
-       DCDest = DC_LockDc(hDCDest);\r
-       if (NULL == DCDest)\r
-       {\r
-               DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);\r
-               return FALSE;\r
-       }\r
-       if (DCDest->DC_Type == DC_TYPE_INFO)\r
-       {\r
-               DC_UnlockDc(DCDest);\r
-               /* Yes, Windows really returns TRUE in this case */\r
-               return TRUE;\r
-       }\r
-\r
-       if (UsesSource)\r
-       {\r
-               if (hDCSrc != hDCDest)\r
-               {\r
-                       DCSrc = DC_LockDc(hDCSrc);\r
-                       if (NULL == DCSrc)\r
-                       {\r
-                               DC_UnlockDc(DCDest);\r
-                               DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);\r
-                               return FALSE;\r
-                       }\r
-                       if (DCSrc->DC_Type == DC_TYPE_INFO)\r
-                       {\r
-                               DC_UnlockDc(DCSrc);\r
-                               DC_UnlockDc(DCDest);\r
-                               /* Yes, Windows really returns TRUE in this case */\r
-                               return TRUE;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       DCSrc = DCDest;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               DCSrc = NULL;\r
-       }\r
-\r
-       Dc_Attr = DCDest->pDc_Attr;\r
-       if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;\r
-\r
-       /* Offset the destination and source by the origin of their DCs. */\r
-        XDest += DCDest->ptlDCOrig.x;\r
-        YDest += DCDest->ptlDCOrig.y;\r
-       if (UsesSource)\r
-       {\r
-               XSrc += DCSrc->ptlDCOrig.x;\r
-               YSrc += DCSrc->ptlDCOrig.y;\r
-       }\r
-\r
-       DestRect.left   = XDest;\r
-       DestRect.top    = YDest;\r
-       DestRect.right  = XDest+Width;\r
-       DestRect.bottom = YDest+Height;\r
-\r
-       IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);\r
-\r
-       SourcePoint.x = XSrc;\r
-       SourcePoint.y = YSrc;\r
-\r
-       BrushOrigin.x = 0;\r
-       BrushOrigin.y = 0;\r
-\r
-       /* Determine surfaces to be used in the bitblt */\r
-       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
-       if (!BitmapDest)\r
-               goto cleanup;\r
-\r
-       if (UsesSource)\r
-       {\r
-               if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
-                       BitmapSrc = BitmapDest;\r
-               else\r
-               {\r
-                       BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
-                       if (!BitmapSrc)\r
-                               goto cleanup;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               BitmapSrc = NULL;\r
-       }\r
-\r
-       if (UsesPattern)\r
-       {\r
-               BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
-               if (NULL == BrushObj)\r
-               {\r
-                       SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-                       goto cleanup;\r
-               }\r
-               BrushOrigin = *((PPOINTL)&BrushObj->ptOrigin);\r
-               IntGdiInitBrushInstance(&BrushInst, BrushObj, DCDest->XlateBrush);\r
-       }\r
-       else\r
-       {\r
-               BrushObj = NULL;\r
-       }\r
-\r
-       /* Create the XLATEOBJ. */\r
-       if (UsesSource)\r
-       {\r
-               XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
-\r
-               if (XlateObj == (XLATEOBJ*)-1)\r
-               {\r
-                       DPRINT1("error!\n");\r
-                       SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
-                       XlateObj = NULL;\r
-                       goto cleanup;\r
-               }\r
-       }\r
-\r
-       /* Perform the bitblt operation */\r
-    Status = IntEngBitBlt( BitmapDest ? &BitmapDest->SurfObj : NULL, BitmapSrc ? &BitmapSrc->SurfObj : NULL, NULL,\r
-                          DCDest->CombinedClip, XlateObj, &DestRect,\r
-                          &SourcePoint, NULL,\r
-                          BrushObj ? &BrushInst.BrushObject : NULL,\r
-                          &BrushOrigin, ROP3_TO_ROP4(ROP));\r
-\r
-cleanup:\r
-       if (UsesSource && XlateObj != NULL)\r
-               EngDeleteXlate(XlateObj);\r
-\r
-       if(BitmapDest != NULL)\r
-       {\r
-               BITMAPOBJ_UnlockBitmap(BitmapDest);\r
-       }\r
-       if (UsesSource && BitmapSrc != BitmapDest)\r
-       {\r
-               BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
-       }\r
-       if (BrushObj != NULL)\r
-       {\r
-               BRUSHOBJ_UnlockBrush(BrushObj);\r
-       }\r
-       if (UsesSource && hDCSrc != hDCDest)\r
-       {\r
-               DC_UnlockDc(DCSrc);\r
-       }\r
-       DC_UnlockDc(DCDest);\r
-\r
-       return Status;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiTransparentBlt(\r
-       HDC                     hdcDst,\r
-       INT                     xDst,\r
-       INT                     yDst,\r
-       INT                     cxDst,\r
-       INT                     cyDst,\r
-       HDC                     hdcSrc,\r
-       INT                     xSrc,\r
-       INT                     ySrc,\r
-       INT                     cxSrc,\r
-       INT                     cySrc,\r
-       COLORREF        TransColor)\r
-{\r
-  PDC DCDest, DCSrc;\r
-  RECTL rcDest, rcSrc;\r
-  BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;\r
-  XLATEOBJ *XlateObj = NULL;\r
-  HPALETTE SourcePalette = 0, DestPalette = 0;\r
-  PPALGDI PalDestGDI, PalSourceGDI;\r
-  USHORT PalDestMode, PalSrcMode;\r
-  ULONG TransparentColor = 0;\r
-  BOOL Ret = FALSE;\r
-\r
-  if(!(DCDest = DC_LockDc(hdcDst)))\r
-  {\r
-    DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);\r
-    SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-    return FALSE;\r
-  }\r
-  if (DCDest->DC_Type == DC_TYPE_INFO)\r
-  {\r
-    DC_UnlockDc(DCDest);\r
-    /* Yes, Windows really returns TRUE in this case */\r
-    return TRUE;\r
-  }\r
-\r
-  if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))\r
-  {\r
-    DC_UnlockDc(DCDest);\r
-    DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);\r
-    SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-    return FALSE;\r
-  }\r
-  if(hdcDst == hdcSrc)\r
-  {\r
-    DCSrc = DCDest;\r
-  }\r
-  if (DCSrc->DC_Type == DC_TYPE_INFO)\r
-  {\r
-    DC_UnlockDc(DCSrc);\r
-    if(hdcDst != hdcSrc)\r
-    {\r
-      DC_UnlockDc(DCDest);\r
-    }\r
-    /* Yes, Windows really returns TRUE in this case */\r
-    return TRUE;\r
-  }\r
-\r
-  /* Offset positions */\r
-  xDst += DCDest->ptlDCOrig.x;\r
-  yDst += DCDest->ptlDCOrig.y;\r
-  xSrc += DCSrc->ptlDCOrig.x;\r
-  ySrc += DCSrc->ptlDCOrig.y;\r
-\r
-  BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
-  if (!BitmapDest)\r
-  {\r
-    goto done;\r
-  }\r
-\r
-  BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
-  if (!BitmapSrc)\r
-  {\r
-    goto done;\r
-  }\r
-\r
-  DestPalette = BitmapDest->hDIBPalette;\r
-  if (!DestPalette) DestPalette = pPrimarySurface->DevInfo.hpalDefault;\r
-\r
-  SourcePalette = BitmapSrc->hDIBPalette;\r
-  if (!SourcePalette) SourcePalette = pPrimarySurface->DevInfo.hpalDefault;\r
-\r
-  if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))\r
-  {\r
-    SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-    goto done;\r
-  }\r
-  PalSrcMode = PalSourceGDI->Mode;\r
-  PALETTE_UnlockPalette(PalSourceGDI);\r
-\r
-  if(DestPalette != SourcePalette)\r
-  {\r
-    if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))\r
-    {\r
-      SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-      goto done;\r
-    }\r
-    PalDestMode = PalDestGDI->Mode;\r
-    PALETTE_UnlockPalette(PalDestGDI);\r
-  }\r
-  else\r
-  {\r
-    PalDestMode = PalSrcMode;\r
-  }\r
-\r
-  /* Translate Transparent (RGB) Color to the source palette */\r
-  if((XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalSrcMode, PAL_RGB, SourcePalette, NULL)))\r
-  {\r
-    TransparentColor = XLATEOBJ_iXlate(XlateObj, (ULONG)TransColor);\r
-    EngDeleteXlate(XlateObj);\r
-  }\r
-\r
-  /* Create the XLATE object to convert colors between source and destination */\r
-  XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalDestMode, PalSrcMode, DestPalette, SourcePalette);\r
-\r
-  rcDest.left = xDst;\r
-  rcDest.top = yDst;\r
-  rcDest.right = rcDest.left + cxDst;\r
-  rcDest.bottom = rcDest.top + cyDst;\r
-  rcSrc.left = xSrc;\r
-  rcSrc.top = ySrc;\r
-  rcSrc.right = rcSrc.left + cxSrc;\r
-  rcSrc.bottom = rcSrc.top + cySrc;\r
-\r
-  if((cxDst != cxSrc) || (cyDst != cySrc))\r
-  {\r
-    DPRINT1("TransparentBlt() does not support stretching at the moment!\n");\r
-    goto done;\r
-  }\r
-\r
-  Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
-                             DCDest->CombinedClip, XlateObj, &rcDest, &rcSrc,\r
-                             TransparentColor, 0);\r
-\r
-done:\r
-  DC_UnlockDc(DCSrc);\r
-  if (BitmapDest)\r
-  {\r
-    BITMAPOBJ_UnlockBitmap(BitmapDest);\r
-  }\r
-  if (BitmapSrc)\r
-  {\r
-    BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
-  }\r
-  if(hdcDst != hdcSrc)\r
-  {\r
-    DC_UnlockDc(DCDest);\r
-  }\r
-  if(XlateObj)\r
-  {\r
-    EngDeleteXlate(XlateObj);\r
-  }\r
-  return Ret;\r
-}\r
-\r
-/***********************************************************************\r
- * MaskBlt\r
- * Ported from WINE by sedwards 11-4-03\r
- *\r
- * Someone thought it would be faster to do it here and then switch back\r
- * to GDI32. I dunno. Write a test and let me know.\r
- */\r
-\r
-static __inline BYTE\r
-SwapROP3_SrcDst(BYTE bRop3)\r
-{\r
-       return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);\r
-}\r
-\r
-#define FRGND_ROP3(ROP4)       ((ROP4) & 0x00FFFFFF)\r
-#define BKGND_ROP3(ROP4)       (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])\r
-#define DSTCOPY                0x00AA0029\r
-#define DSTERASE               0x00220326 /* dest = dest & (~src) : DSna */\r
-\r
-BOOL STDCALL\r
-NtGdiMaskBlt (\r
-       HDC hdcDest, INT nXDest, INT nYDest,\r
-       INT nWidth, INT nHeight, HDC hdcSrc,\r
-       INT nXSrc, INT nYSrc, HBITMAP hbmMask,\r
-       INT xMask, INT yMask, DWORD dwRop,\r
-       IN DWORD crBackColor)\r
-{\r
-       HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;\r
-       HDC hDCMask, hDC1, hDC2;\r
-       static const DWORD ROP3Table[256] =\r
-       {\r
-               0x00000042, 0x00010289,\r
-               0x00020C89, 0x000300AA,\r
-               0x00040C88, 0x000500A9,\r
-               0x00060865, 0x000702C5,\r
-               0x00080F08, 0x00090245,\r
-               0x000A0329, 0x000B0B2A,\r
-               0x000C0324, 0x000D0B25,\r
-               0x000E08A5, 0x000F0001,\r
-               0x00100C85, 0x001100A6,\r
-               0x00120868, 0x001302C8,\r
-               0x00140869, 0x001502C9,\r
-               0x00165CCA, 0x00171D54,\r
-               0x00180D59, 0x00191CC8,\r
-               0x001A06C5, 0x001B0768,\r
-               0x001C06CA, 0x001D0766,\r
-               0x001E01A5, 0x001F0385,\r
-               0x00200F09, 0x00210248,\r
-               0x00220326, 0x00230B24,\r
-               0x00240D55, 0x00251CC5,\r
-               0x002606C8, 0x00271868,\r
-               0x00280369, 0x002916CA,\r
-               0x002A0CC9, 0x002B1D58,\r
-               0x002C0784, 0x002D060A,\r
-               0x002E064A, 0x002F0E2A,\r
-               0x0030032A, 0x00310B28,\r
-               0x00320688, 0x00330008,\r
-               0x003406C4, 0x00351864,\r
-               0x003601A8, 0x00370388,\r
-               0x0038078A, 0x00390604,\r
-               0x003A0644, 0x003B0E24,\r
-               0x003C004A, 0x003D18A4,\r
-               0x003E1B24, 0x003F00EA,\r
-               0x00400F0A, 0x00410249,\r
-               0x00420D5D, 0x00431CC4,\r
-               0x00440328, 0x00450B29,\r
-               0x004606C6, 0x0047076A,\r
-               0x00480368, 0x004916C5,\r
-               0x004A0789, 0x004B0605,\r
-               0x004C0CC8, 0x004D1954,\r
-               0x004E0645, 0x004F0E25,\r
-               0x00500325, 0x00510B26,\r
-               0x005206C9, 0x00530764,\r
-               0x005408A9, 0x00550009,\r
-               0x005601A9, 0x00570389,\r
-               0x00580785, 0x00590609,\r
-               0x005A0049, 0x005B18A9,\r
-               0x005C0649, 0x005D0E29,\r
-               0x005E1B29, 0x005F00E9,\r
-               0x00600365, 0x006116C6,\r
-               0x00620786, 0x00630608,\r
-               0x00640788, 0x00650606,\r
-               0x00660046, 0x006718A8,\r
-               0x006858A6, 0x00690145,\r
-               0x006A01E9, 0x006B178A,\r
-               0x006C01E8, 0x006D1785,\r
-               0x006E1E28, 0x006F0C65,\r
-               0x00700CC5, 0x00711D5C,\r
-               0x00720648, 0x00730E28,\r
-               0x00740646, 0x00750E26,\r
-               0x00761B28, 0x007700E6,\r
-               0x007801E5, 0x00791786,\r
-               0x007A1E29, 0x007B0C68,\r
-               0x007C1E24, 0x007D0C69,\r
-               0x007E0955, 0x007F03C9,\r
-               0x008003E9, 0x00810975,\r
-               0x00820C49, 0x00831E04,\r
-               0x00840C48, 0x00851E05,\r
-               0x008617A6, 0x008701C5,\r
-               0x008800C6, 0x00891B08,\r
-               0x008A0E06, 0x008B0666,\r
-               0x008C0E08, 0x008D0668,\r
-               0x008E1D7C, 0x008F0CE5,\r
-               0x00900C45, 0x00911E08,\r
-               0x009217A9, 0x009301C4,\r
-               0x009417AA, 0x009501C9,\r
-               0x00960169, 0x0097588A,\r
-               0x00981888, 0x00990066,\r
-               0x009A0709, 0x009B07A8,\r
-               0x009C0704, 0x009D07A6,\r
-               0x009E16E6, 0x009F0345,\r
-               0x00A000C9, 0x00A11B05,\r
-               0x00A20E09, 0x00A30669,\r
-               0x00A41885, 0x00A50065,\r
-               0x00A60706, 0x00A707A5,\r
-               0x00A803A9, 0x00A90189,\r
-               0x00AA0029, 0x00AB0889,\r
-               0x00AC0744, 0x00AD06E9,\r
-               0x00AE0B06, 0x00AF0229,\r
-               0x00B00E05, 0x00B10665,\r
-               0x00B21974, 0x00B30CE8,\r
-               0x00B4070A, 0x00B507A9,\r
-               0x00B616E9, 0x00B70348,\r
-               0x00B8074A, 0x00B906E6,\r
-               0x00BA0B09, 0x00BB0226,\r
-               0x00BC1CE4, 0x00BD0D7D,\r
-               0x00BE0269, 0x00BF08C9,\r
-               0x00C000CA, 0x00C11B04,\r
-               0x00C21884, 0x00C3006A,\r
-               0x00C40E04, 0x00C50664,\r
-               0x00C60708, 0x00C707AA,\r
-               0x00C803A8, 0x00C90184,\r
-               0x00CA0749, 0x00CB06E4,\r
-               0x00CC0020, 0x00CD0888,\r
-               0x00CE0B08, 0x00CF0224,\r
-               0x00D00E0A, 0x00D1066A,\r
-               0x00D20705, 0x00D307A4,\r
-               0x00D41D78, 0x00D50CE9,\r
-               0x00D616EA, 0x00D70349,\r
-               0x00D80745, 0x00D906E8,\r
-               0x00DA1CE9, 0x00DB0D75,\r
-               0x00DC0B04, 0x00DD0228,\r
-               0x00DE0268, 0x00DF08C8,\r
-               0x00E003A5, 0x00E10185,\r
-               0x00E20746, 0x00E306EA,\r
-               0x00E40748, 0x00E506E5,\r
-               0x00E61CE8, 0x00E70D79,\r
-               0x00E81D74, 0x00E95CE6,\r
-               0x00EA02E9, 0x00EB0849,\r
-               0x00EC02E8, 0x00ED0848,\r
-               0x00EE0086, 0x00EF0A08,\r
-               0x00F00021, 0x00F10885,\r
-               0x00F20B05, 0x00F3022A,\r
-               0x00F40B0A, 0x00F50225,\r
-               0x00F60265, 0x00F708C5,\r
-               0x00F802E5, 0x00F90845,\r
-               0x00FA0089, 0x00FB0A09,\r
-               0x00FC008A, 0x00FD0A0A,\r
-               0x00FE02A9, 0x00FF0062,\r
-       };\r
-\r
-       if (!hbmMask)\r
-               return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);\r
-\r
-       /* 1. make mask bitmap's dc */\r
-       hDCMask = NtGdiCreateCompatibleDC(hdcDest);\r
-       hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);\r
-\r
-       /* 2. make masked Background bitmap */\r
-\r
-       /* 2.1 make bitmap */\r
-       hDC1 = NtGdiCreateCompatibleDC(hdcDest);\r
-       hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);\r
-       hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);\r
-\r
-       /* 2.2 draw dest bitmap and mask */\r
-       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);\r
-       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);\r
-       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);\r
-\r
-       /* 3. make masked Foreground bitmap */\r
-\r
-       /* 3.1 make bitmap */\r
-       hDC2 = NtGdiCreateCompatibleDC(hdcDest);\r
-       hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);\r
-       hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);\r
-\r
-       /* 3.2 draw src bitmap and mask */\r
-       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);\r
-       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);\r
-       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);\r
-\r
-       /* 4. combine two bitmap and copy it to hdcDest */\r
-       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);\r
-       NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);\r
-\r
-       /* 5. restore all object */\r
-       NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);\r
-       NtGdiSelectBitmap(hDC1, hOldBitmap2);\r
-       NtGdiSelectBitmap(hDC2, hOldBitmap3);\r
-\r
-       /* 6. delete all temp object */\r
-       NtGdiDeleteObject(hBitmap2);\r
-       NtGdiDeleteObject(hBitmap3);\r
-\r
-       NtGdiDeleteObjectApp(hDC1);\r
-       NtGdiDeleteObjectApp(hDC2);\r
-       NtGdiDeleteObjectApp(hDCMask);\r
-\r
-       return TRUE;\r
-}\r
-\r
-BOOL\r
-APIENTRY\r
-NtGdiPlgBlt(\r
-    IN HDC hdcTrg,\r
-    IN LPPOINT pptlTrg,\r
-    IN HDC hdcSrc,\r
-    IN INT xSrc,\r
-    IN INT ySrc,\r
-    IN INT cxSrc,\r
-    IN INT cySrc,\r
-    IN HBITMAP hbmMask,\r
-    IN INT xMask,\r
-    IN INT yMask,\r
-    IN DWORD crBackColor)\r
-{\r
-       UNIMPLEMENTED;\r
-       return FALSE;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiStretchBlt(\r
-       HDC  hDCDest,\r
-       INT  XOriginDest,\r
-       INT  YOriginDest,\r
-       INT  WidthDest,\r
-       INT  HeightDest,\r
-       HDC  hDCSrc,\r
-       INT  XOriginSrc,\r
-       INT  YOriginSrc,\r
-       INT  WidthSrc,\r
-       INT  HeightSrc,\r
-       DWORD  ROP,\r
-       IN DWORD dwBackColor)\r
-{\r
-       PDC DCDest = NULL;\r
-       PDC DCSrc  = NULL;\r
-       PDC_ATTR Dc_Attr;\r
-       BITMAPOBJ *BitmapDest, *BitmapSrc;\r
-       RECTL DestRect;\r
-       RECTL SourceRect;\r
-       BOOL Status;\r
-       XLATEOBJ *XlateObj = NULL;\r
-       PGDIBRUSHOBJ BrushObj = NULL;\r
-       BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);\r
-       BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);\r
-\r
-       if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)\r
-       {\r
-               SetLastWin32Error(ERROR_INVALID_PARAMETER);\r
-               return FALSE;\r
-       }\r
-       DCDest = DC_LockDc(hDCDest);\r
-       if (NULL == DCDest)\r
-       {\r
-               DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);\r
-               SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-               return FALSE;\r
-       }\r
-       if (DCDest->DC_Type == DC_TYPE_INFO)\r
-       {\r
-               DC_UnlockDc(DCDest);\r
-               /* Yes, Windows really returns TRUE in this case */\r
-               return TRUE;\r
-       }\r
-\r
-       if (UsesSource)\r
-       {\r
-               if (hDCSrc != hDCDest)\r
-               {\r
-                       DCSrc = DC_LockDc(hDCSrc);\r
-                       if (NULL == DCSrc)\r
-                       {\r
-                               DC_UnlockDc(DCDest);\r
-                               DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);\r
-                               SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-                               return FALSE;\r
-                       }\r
-                       if (DCSrc->DC_Type == DC_TYPE_INFO)\r
-                       {\r
-                               DC_UnlockDc(DCSrc);\r
-                               DC_UnlockDc(DCDest);\r
-                               /* Yes, Windows really returns TRUE in this case */\r
-                               return TRUE;\r
-                       }\r
-               }\r
-               else\r
-               {\r
-                       DCSrc = DCDest;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               DCSrc = NULL;\r
-       }\r
-\r
-       /* Offset the destination and source by the origin of their DCs. */\r
-       // FIXME: ptlDCOrig is in device coordinates!\r
-       XOriginDest += DCDest->ptlDCOrig.x;\r
-       YOriginDest += DCDest->ptlDCOrig.y;\r
-       if (UsesSource)\r
-       {\r
-               XOriginSrc += DCSrc->ptlDCOrig.x;\r
-               YOriginSrc += DCSrc->ptlDCOrig.y;\r
-       }\r
-\r
-       DestRect.left   = XOriginDest;\r
-       DestRect.top    = YOriginDest;\r
-       DestRect.right  = XOriginDest+WidthDest;\r
-       DestRect.bottom = YOriginDest+HeightDest;\r
-\r
-       SourceRect.left   = XOriginSrc;\r
-       SourceRect.top    = YOriginSrc;\r
-       SourceRect.right  = XOriginSrc+WidthSrc;\r
-       SourceRect.bottom = YOriginSrc+HeightSrc;\r
-\r
-       /* Determine surfaces to be used in the bitblt */\r
-       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);\r
-       if (UsesSource)\r
-       {\r
-               if (DCSrc->w.hBitmap == DCDest->w.hBitmap)\r
-                       BitmapSrc = BitmapDest;\r
-               else\r
-                       BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);\r
-\r
-               int sw = BitmapSrc->SurfObj.sizlBitmap.cx;\r
-               int sh = BitmapSrc->SurfObj.sizlBitmap.cy;\r
-               if ( SourceRect.left < 0 )\r
-               {\r
-                       DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right)/abs(SourceRect.right-SourceRect.left);\r
-                       SourceRect.left = 0;\r
-               }\r
-               if ( SourceRect.top < 0 )\r
-               {\r
-                       DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom)/abs(SourceRect.bottom-SourceRect.top);\r
-                       SourceRect.top = 0;\r
-               }\r
-               if ( SourceRect.right < -1 )\r
-               {\r
-                       DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * (-1-SourceRect.left)/abs(SourceRect.right-SourceRect.left);\r
-                       SourceRect.right = -1;\r
-               }\r
-               if ( SourceRect.bottom < -1 )\r
-               {\r
-                       DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * (-1-SourceRect.top)/abs(SourceRect.bottom-SourceRect.top);\r
-                       SourceRect.bottom = -1;\r
-               }\r
-               if ( SourceRect.right > sw )\r
-               {\r
-                       DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * abs(sw-SourceRect.left) / abs(SourceRect.right-SourceRect.left);\r
-                       SourceRect.right = sw;\r
-               }\r
-               if ( SourceRect.bottom > sh )\r
-               {\r
-                       DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * abs(sh-SourceRect.top) / abs(SourceRect.bottom-SourceRect.top);\r
-                       SourceRect.bottom = sh;\r
-               }\r
-               sw--;\r
-               sh--;\r
-               if ( SourceRect.left > sw )\r
-               {\r
-                       DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right-sw) / abs(SourceRect.right-SourceRect.left);\r
-                       SourceRect.left = 0;\r
-               }\r
-               if ( SourceRect.top > sh )\r
-               {\r
-                       DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom-sh) / abs(SourceRect.bottom-SourceRect.top);\r
-                       SourceRect.top = 0;\r
-               }\r
-               if (0 == (DestRect.right-DestRect.left) || 0 == (DestRect.bottom-DestRect.top) || 0 == (SourceRect.right-SourceRect.left) || 0 == (SourceRect.bottom-SourceRect.top))\r
-               {\r
-                       SetLastWin32Error(ERROR_INVALID_PARAMETER);\r
-                       Status = FALSE;\r
-                       goto failed;\r
-               }\r
-\r
-               /* Create the XLATEOBJ. */\r
-               XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);\r
-               if (XlateObj == (XLATEOBJ*)-1)\r
-               {\r
-                       SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);\r
-                       Status = FALSE;\r
-                       goto failed;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               BitmapSrc = NULL;\r
-       }\r
-\r
-       if (UsesPattern)\r
-       {\r
-               Dc_Attr = DCDest->pDc_Attr;\r
-               if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;\r
-               BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
-               if (NULL == BrushObj)\r
-               {\r
-                       SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-                       Status = FALSE;\r
-                       goto failed;\r
-               }\r
-       }\r
-       else\r
-       {\r
-               BrushObj = NULL;\r
-       }\r
-\r
-       /* Perform the bitblt operation */\r
-       Status = IntEngStretchBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,\r
-                                  NULL, DCDest->CombinedClip, XlateObj,\r
-                                  &DestRect, &SourceRect, NULL, NULL, NULL,\r
-                                  COLORONCOLOR);\r
-\r
-failed:\r
-       if (XlateObj)\r
-       {\r
-               EngDeleteXlate(XlateObj);\r
-       }\r
-       if (BrushObj)\r
-       {\r
-               BRUSHOBJ_UnlockBrush(BrushObj);\r
-       }\r
-       if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)\r
-       {\r
-               BITMAPOBJ_UnlockBitmap(BitmapSrc);\r
-       }\r
-       BITMAPOBJ_UnlockBitmap(BitmapDest);\r
-       if (UsesSource && hDCSrc != hDCDest)\r
-       {\r
-               DC_UnlockDc(DCSrc);\r
-       }\r
-       DC_UnlockDc(DCDest);\r
-\r
-       return Status;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntPatBlt(\r
-   PDC dc,\r
-   INT XLeft,\r
-   INT YLeft,\r
-   INT Width,\r
-   INT Height,\r
-   DWORD ROP,\r
-   PGDIBRUSHOBJ BrushObj)\r
-{\r
-   RECTL DestRect;\r
-   BITMAPOBJ *BitmapObj;\r
-   GDIBRUSHINST BrushInst;\r
-   POINTL BrushOrigin;\r
-   BOOL ret = TRUE;\r
-\r
-   ASSERT(BrushObj);\r
-\r
-   BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);\r
-   if (BitmapObj == NULL)\r
-   {\r
-      SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-      return FALSE;\r
-   }\r
-\r
-   if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))\r
-   {\r
-      if (Width > 0)\r
-      {\r
-         DestRect.left = XLeft + dc->ptlDCOrig.x;\r
-         DestRect.right = XLeft + Width + dc->ptlDCOrig.x;\r
-      }\r
-      else\r
-      {\r
-         DestRect.left = XLeft + Width + 1 + dc->ptlDCOrig.x;\r
-         DestRect.right = XLeft + dc->ptlDCOrig.x + 1;\r
-      }\r
-\r
-      if (Height > 0)\r
-      {\r
-         DestRect.top = YLeft + dc->ptlDCOrig.y;\r
-         DestRect.bottom = YLeft + Height + dc->ptlDCOrig.y;\r
-      }\r
-      else\r
-      {\r
-         DestRect.top = YLeft + Height + dc->ptlDCOrig.y + 1;\r
-         DestRect.bottom = YLeft + dc->ptlDCOrig.y + 1;\r
-      }\r
-\r
-      IntLPtoDP(dc, (LPPOINT)&DestRect, 2);\r
-\r
-      BrushOrigin.x = BrushObj->ptOrigin.x + dc->ptlDCOrig.x;\r
-      BrushOrigin.y = BrushObj->ptOrigin.y + dc->ptlDCOrig.y;\r
-\r
-      IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);\r
-\r
-      ret = IntEngBitBlt(\r
-         &BitmapObj->SurfObj,\r
-         NULL,\r
-         NULL,\r
-         dc->CombinedClip,\r
-         NULL,\r
-         &DestRect,\r
-         NULL,\r
-         NULL,\r
-         &BrushInst.BrushObject, // use pDC->eboFill\r
-         &BrushOrigin,\r
-         ROP3_TO_ROP4(ROP));\r
-   }\r
-\r
-   BITMAPOBJ_UnlockBitmap(BitmapObj);\r
-\r
-   return ret;\r
-}\r
-\r
-BOOL FASTCALL\r
-IntGdiPolyPatBlt(\r
-   HDC hDC,\r
-   DWORD dwRop,\r
-   PPATRECT pRects,\r
-   int cRects,\r
-   ULONG Reserved)\r
-{\r
-   int i;\r
-   PPATRECT r;\r
-   PGDIBRUSHOBJ BrushObj;\r
-   DC *dc;\r
-\r
-   dc = DC_LockDc(hDC);\r
-   if (dc == NULL)\r
-   {\r
-      SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-      return FALSE;\r
-   }\r
-   if (dc->DC_Type == DC_TYPE_INFO)\r
-   {\r
-      DC_UnlockDc(dc);\r
-      /* Yes, Windows really returns TRUE in this case */\r
-      return TRUE;\r
-   }\r
-\r
-   for (r = pRects, i = 0; i < cRects; i++)\r
-   {\r
-      BrushObj = BRUSHOBJ_LockBrush(r->hBrush);\r
-      if(BrushObj != NULL)\r
-      {\r
-        IntPatBlt(\r
-           dc,\r
-           r->r.left,\r
-           r->r.top,\r
-           r->r.right,\r
-           r->r.bottom,\r
-           dwRop,\r
-           BrushObj);\r
-        BRUSHOBJ_UnlockBrush(BrushObj);\r
-      }\r
-      r++;\r
-   }\r
-\r
-   DC_UnlockDc(dc);\r
-\r
-   return TRUE;\r
-}\r
-\r
-\r
-BOOL STDCALL\r
-NtGdiPatBlt(\r
-   HDC hDC,\r
-   INT XLeft,\r
-   INT YLeft,\r
-   INT Width,\r
-   INT Height,\r
-   DWORD ROP)\r
-{\r
-   PGDIBRUSHOBJ BrushObj;\r
-   DC *dc;\r
-   PDC_ATTR Dc_Attr;\r
-   BOOL ret;\r
-\r
-   BOOL UsesSource = ROP3_USES_SOURCE(ROP);\r
-   if (UsesSource)\r
-   {\r
-       /* in this case we call on GdiMaskBlt */\r
-       return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);\r
-   }\r
-\r
-   dc = DC_LockDc(hDC);\r
-   if (dc == NULL)\r
-   {\r
-      SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-      return FALSE;\r
-   }\r
-   Dc_Attr = dc->pDc_Attr;\r
-   if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;\r
-   if (dc->DC_Type == DC_TYPE_INFO)\r
-   {\r
-      DC_UnlockDc(dc);\r
-      /* Yes, Windows really returns TRUE in this case */\r
-      return TRUE;\r
-   }\r
-\r
-   BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);\r
-   if (BrushObj == NULL)\r
-   {\r
-      SetLastWin32Error(ERROR_INVALID_HANDLE);\r
-      DC_UnlockDc(dc);\r
-      return FALSE;\r
-   }\r
-\r
-   ret = IntPatBlt(\r
-      dc,\r
-      XLeft,\r
-      YLeft,\r
-      Width,\r
-      Height,\r
-      ROP,\r
-      BrushObj);\r
-\r
-   BRUSHOBJ_UnlockBrush(BrushObj);\r
-   DC_UnlockDc(dc);\r
-\r
-   return ret;\r
-}\r
-\r
-BOOL STDCALL\r
-NtGdiPolyPatBlt(\r
-   HDC hDC,\r
-   DWORD dwRop,\r
-   IN PPOLYPATBLT pRects,\r
-   IN DWORD cRects,\r
-   IN DWORD Mode)\r
-{\r
-   PPATRECT rb = NULL;\r
-   NTSTATUS Status = STATUS_SUCCESS;\r
-   BOOL Ret;\r
-\r
-   if (cRects > 0)\r
-   {\r
-      rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);\r
-      if (!rb)\r
-      {\r
-         SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);\r
-         return FALSE;\r
-      }\r
-      _SEH_TRY\r
-      {\r
-         ProbeForRead(pRects,\r
-                      cRects * sizeof(PATRECT),\r
-                      1);\r
-         RtlCopyMemory(rb,\r
-                       pRects,\r
-                       cRects * sizeof(PATRECT));\r
-      }\r
-      _SEH_HANDLE\r
-      {\r
-         Status = _SEH_GetExceptionCode();\r
-      }\r
-      _SEH_END;\r
-\r
-      if (!NT_SUCCESS(Status))\r
-      {\r
-         ExFreePool(rb);\r
-         SetLastNtError(Status);\r
-         return FALSE;\r
-      }\r
-   }\r
-\r
-   Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);\r
-\r
-   if (cRects > 0)\r
-      ExFreePool(rb);\r
-\r
-   return Ret;\r
-}\r
+/*
+ *  ReactOS W32 Subsystem
+ *  Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  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.
+ */
+/* $Id: bitmaps.c 28300 2007-08-12 15:20:09Z tkreuzer $ */
+
+#include <w32k.h>
+
+#define NDEBUG
+#include <debug.h>
+
+
+
+BOOL STDCALL
+NtGdiAlphaBlend(
+       HDC  hDCDest,
+       LONG  XOriginDest,
+       LONG  YOriginDest,
+       LONG  WidthDest,
+       LONG  HeightDest,
+       HDC  hDCSrc,
+       LONG  XOriginSrc,
+       LONG  YOriginSrc,
+       LONG  WidthSrc,
+       LONG  HeightSrc,
+       BLENDFUNCTION  BlendFunc,
+       HANDLE hcmXform)
+{
+       PDC DCDest = NULL;
+       PDC DCSrc  = NULL;
+       BITMAPOBJ *BitmapDest, *BitmapSrc;
+       RECTL DestRect, SourceRect;
+       BOOL Status;
+       XLATEOBJ *XlateObj;
+       BLENDOBJ BlendObj;
+       BlendObj.BlendFunction = BlendFunc;
+
+       DCDest = DC_LockDc(hDCDest);
+       if (NULL == DCDest)
+       {
+               DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCDest);
+               SetLastWin32Error(ERROR_INVALID_HANDLE);
+               return FALSE;
+       }
+       if (DCDest->DC_Type == DC_TYPE_INFO)
+       {
+               DC_UnlockDc(DCDest);
+               /* Yes, Windows really returns TRUE in this case */
+               return TRUE;
+       }
+
+       if (hDCSrc != hDCDest)
+       {
+               DCSrc = DC_LockDc(hDCSrc);
+               if (NULL == DCSrc)
+               {
+                       DC_UnlockDc(DCDest);
+                       DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiAlphaBlend\n", hDCSrc);
+                       SetLastWin32Error(ERROR_INVALID_HANDLE);
+                       return FALSE;
+               }
+               if (DCSrc->DC_Type == DC_TYPE_INFO)
+               {
+                       DC_UnlockDc(DCSrc);
+                       DC_UnlockDc(DCDest);
+                       /* Yes, Windows really returns TRUE in this case */
+                       return TRUE;
+               }
+       }
+       else
+       {
+               DCSrc = DCDest;
+       }
+
+       /* Offset the destination and source by the origin of their DCs. */
+       XOriginDest += DCDest->ptlDCOrig.x;
+       YOriginDest += DCDest->ptlDCOrig.y;
+       XOriginSrc += DCSrc->ptlDCOrig.x;
+       YOriginSrc += DCSrc->ptlDCOrig.y;
+
+       DestRect.left   = XOriginDest;
+       DestRect.top    = YOriginDest;
+       DestRect.right  = XOriginDest + WidthDest;
+       DestRect.bottom = YOriginDest + HeightDest;
+
+       SourceRect.left   = XOriginSrc;
+       SourceRect.top    = YOriginSrc;
+       SourceRect.right  = XOriginSrc + WidthSrc;
+       SourceRect.bottom = YOriginSrc + HeightSrc;
+
+       /* Determine surfaces to be used in the bitblt */
+       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+       if (!BitmapDest)
+       {
+               DC_UnlockDc(DCSrc);
+               DC_UnlockDc(DCDest);
+               return FALSE;
+       }
+       if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+               BitmapSrc = BitmapDest;
+       else
+       {
+               BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+               if (!BitmapDest)
+               {
+                       BITMAPOBJ_UnlockBitmap(BitmapDest);
+                       DC_UnlockDc(DCSrc);
+                       DC_UnlockDc(DCDest);
+                       return FALSE;
+               }
+       }
+
+       /* Create the XLATEOBJ. */
+       XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+
+       if (XlateObj == (XLATEOBJ*)-1)
+       {
+               DPRINT1("error!!!\n");
+               SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+               XlateObj = NULL;
+               Status = FALSE;
+       }
+       else
+       {
+               /* Perform the alpha blend operation */
+               Status = IntEngAlphaBlend(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+                                         DCDest->CombinedClip, XlateObj,
+                                         &DestRect, &SourceRect, &BlendObj);
+       }
+
+       if (XlateObj != NULL)
+               EngDeleteXlate(XlateObj);
+
+       BITMAPOBJ_UnlockBitmap(BitmapDest);
+       if (BitmapSrc != BitmapDest)
+               BITMAPOBJ_UnlockBitmap(BitmapSrc);
+       DC_UnlockDc(DCDest);
+       if (hDCSrc != hDCDest)
+               DC_UnlockDc(DCSrc);
+
+       return Status;
+}
+
+BOOL STDCALL
+NtGdiBitBlt(
+       HDC  hDCDest,
+       INT  XDest,
+       INT  YDest,
+       INT  Width,
+       INT  Height,
+       HDC  hDCSrc,
+       INT  XSrc,
+       INT  YSrc,
+       DWORD  ROP,
+       IN DWORD crBackColor,
+       IN FLONG fl)
+{
+       PDC DCDest = NULL;
+       PDC DCSrc  = NULL;
+       PDC_ATTR Dc_Attr = NULL;
+       BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;
+       RECTL DestRect;
+       POINTL SourcePoint, BrushOrigin;
+       BOOL Status = FALSE;
+       XLATEOBJ *XlateObj = NULL;
+       PGDIBRUSHOBJ BrushObj = NULL;
+       GDIBRUSHINST BrushInst;
+       BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+       BOOL UsesPattern = ROP3_USES_PATTERN(ROP);
+
+       DCDest = DC_LockDc(hDCDest);
+       if (NULL == DCDest)
+       {
+               DPRINT("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
+               return FALSE;
+       }
+       if (DCDest->DC_Type == DC_TYPE_INFO)
+       {
+               DC_UnlockDc(DCDest);
+               /* Yes, Windows really returns TRUE in this case */
+               return TRUE;
+       }
+
+       if (UsesSource)
+       {
+               if (hDCSrc != hDCDest)
+               {
+                       DCSrc = DC_LockDc(hDCSrc);
+                       if (NULL == DCSrc)
+                       {
+                               DC_UnlockDc(DCDest);
+                               DPRINT("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
+                               return FALSE;
+                       }
+                       if (DCSrc->DC_Type == DC_TYPE_INFO)
+                       {
+                               DC_UnlockDc(DCSrc);
+                               DC_UnlockDc(DCDest);
+                               /* Yes, Windows really returns TRUE in this case */
+                               return TRUE;
+                       }
+               }
+               else
+               {
+                       DCSrc = DCDest;
+               }
+       }
+       else
+       {
+               DCSrc = NULL;
+       }
+
+       Dc_Attr = DCDest->pDc_Attr;
+       if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;
+
+       /* Offset the destination and source by the origin of their DCs. */
+        XDest += DCDest->ptlDCOrig.x;
+        YDest += DCDest->ptlDCOrig.y;
+       if (UsesSource)
+       {
+               XSrc += DCSrc->ptlDCOrig.x;
+               YSrc += DCSrc->ptlDCOrig.y;
+       }
+
+       DestRect.left   = XDest;
+       DestRect.top    = YDest;
+       DestRect.right  = XDest+Width;
+       DestRect.bottom = YDest+Height;
+
+       IntLPtoDP(DCDest, (LPPOINT)&DestRect, 2);
+
+       SourcePoint.x = XSrc;
+       SourcePoint.y = YSrc;
+
+       BrushOrigin.x = 0;
+       BrushOrigin.y = 0;
+
+       /* Determine surfaces to be used in the bitblt */
+       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+       if (!BitmapDest)
+               goto cleanup;
+
+       if (UsesSource)
+       {
+               if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+                       BitmapSrc = BitmapDest;
+               else
+               {
+                       BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+                       if (!BitmapSrc)
+                               goto cleanup;
+               }
+       }
+       else
+       {
+               BitmapSrc = NULL;
+       }
+
+       if (UsesPattern)
+       {
+               BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+               if (NULL == BrushObj)
+               {
+                       SetLastWin32Error(ERROR_INVALID_HANDLE);
+                       goto cleanup;
+               }
+               BrushOrigin = *((PPOINTL)&BrushObj->ptOrigin);
+               IntGdiInitBrushInstance(&BrushInst, BrushObj, DCDest->XlateBrush);
+       }
+       else
+       {
+               BrushObj = NULL;
+       }
+
+       /* Create the XLATEOBJ. */
+       if (UsesSource)
+       {
+               XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+
+               if (XlateObj == (XLATEOBJ*)-1)
+               {
+                       DPRINT1("error!\n");
+                       SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+                       XlateObj = NULL;
+                       goto cleanup;
+               }
+       }
+
+       /* Perform the bitblt operation */
+    Status = IntEngBitBlt( BitmapDest ? &BitmapDest->SurfObj : NULL, BitmapSrc ? &BitmapSrc->SurfObj : NULL, NULL,
+                          DCDest->CombinedClip, XlateObj, &DestRect,
+                          &SourcePoint, NULL,
+                          BrushObj ? &BrushInst.BrushObject : NULL,
+                          &BrushOrigin, ROP3_TO_ROP4(ROP));
+
+cleanup:
+       if (UsesSource && XlateObj != NULL)
+               EngDeleteXlate(XlateObj);
+
+       if(BitmapDest != NULL)
+       {
+               BITMAPOBJ_UnlockBitmap(BitmapDest);
+       }
+       if (UsesSource && BitmapSrc != BitmapDest)
+       {
+               BITMAPOBJ_UnlockBitmap(BitmapSrc);
+       }
+       if (BrushObj != NULL)
+       {
+               BRUSHOBJ_UnlockBrush(BrushObj);
+       }
+       if (UsesSource && hDCSrc != hDCDest)
+       {
+               DC_UnlockDc(DCSrc);
+       }
+       DC_UnlockDc(DCDest);
+
+       return Status;
+}
+
+BOOL STDCALL
+NtGdiTransparentBlt(
+       HDC                     hdcDst,
+       INT                     xDst,
+       INT                     yDst,
+       INT                     cxDst,
+       INT                     cyDst,
+       HDC                     hdcSrc,
+       INT                     xSrc,
+       INT                     ySrc,
+       INT                     cxSrc,
+       INT                     cySrc,
+       COLORREF        TransColor)
+{
+  PDC DCDest, DCSrc;
+  RECTL rcDest, rcSrc;
+  BITMAPOBJ *BitmapDest, *BitmapSrc = NULL;
+  XLATEOBJ *XlateObj = NULL;
+  HPALETTE SourcePalette = 0, DestPalette = 0;
+  PPALGDI PalDestGDI, PalSourceGDI;
+  USHORT PalDestMode, PalSrcMode;
+  ULONG TransparentColor = 0;
+  BOOL Ret = FALSE;
+
+  if(!(DCDest = DC_LockDc(hdcDst)))
+  {
+    DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcDst);
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+  if (DCDest->DC_Type == DC_TYPE_INFO)
+  {
+    DC_UnlockDc(DCDest);
+    /* Yes, Windows really returns TRUE in this case */
+    return TRUE;
+  }
+
+  if((hdcDst != hdcSrc) && !(DCSrc = DC_LockDc(hdcSrc)))
+  {
+    DC_UnlockDc(DCDest);
+    DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiTransparentBlt\n", hdcSrc);
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    return FALSE;
+  }
+  if(hdcDst == hdcSrc)
+  {
+    DCSrc = DCDest;
+  }
+  if (DCSrc->DC_Type == DC_TYPE_INFO)
+  {
+    DC_UnlockDc(DCSrc);
+    if(hdcDst != hdcSrc)
+    {
+      DC_UnlockDc(DCDest);
+    }
+    /* Yes, Windows really returns TRUE in this case */
+    return TRUE;
+  }
+
+  /* Offset positions */
+  xDst += DCDest->ptlDCOrig.x;
+  yDst += DCDest->ptlDCOrig.y;
+  xSrc += DCSrc->ptlDCOrig.x;
+  ySrc += DCSrc->ptlDCOrig.y;
+
+  BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+  if (!BitmapDest)
+  {
+    goto done;
+  }
+
+  BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+  if (!BitmapSrc)
+  {
+    goto done;
+  }
+
+  DestPalette = BitmapDest->hDIBPalette;
+  if (!DestPalette) DestPalette = pPrimarySurface->DevInfo.hpalDefault;
+
+  SourcePalette = BitmapSrc->hDIBPalette;
+  if (!SourcePalette) SourcePalette = pPrimarySurface->DevInfo.hpalDefault;
+
+  if(!(PalSourceGDI = PALETTE_LockPalette(SourcePalette)))
+  {
+    SetLastWin32Error(ERROR_INVALID_HANDLE);
+    goto done;
+  }
+  PalSrcMode = PalSourceGDI->Mode;
+  PALETTE_UnlockPalette(PalSourceGDI);
+
+  if(DestPalette != SourcePalette)
+  {
+    if (!(PalDestGDI = PALETTE_LockPalette(DestPalette)))
+    {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      goto done;
+    }
+    PalDestMode = PalDestGDI->Mode;
+    PALETTE_UnlockPalette(PalDestGDI);
+  }
+  else
+  {
+    PalDestMode = PalSrcMode;
+  }
+
+  /* Translate Transparent (RGB) Color to the source palette */
+  if((XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalSrcMode, PAL_RGB, SourcePalette, NULL)))
+  {
+    TransparentColor = XLATEOBJ_iXlate(XlateObj, (ULONG)TransColor);
+    EngDeleteXlate(XlateObj);
+  }
+
+  /* Create the XLATE object to convert colors between source and destination */
+  XlateObj = (XLATEOBJ*)IntEngCreateXlate(PalDestMode, PalSrcMode, DestPalette, SourcePalette);
+
+  rcDest.left = xDst;
+  rcDest.top = yDst;
+  rcDest.right = rcDest.left + cxDst;
+  rcDest.bottom = rcDest.top + cyDst;
+  rcSrc.left = xSrc;
+  rcSrc.top = ySrc;
+  rcSrc.right = rcSrc.left + cxSrc;
+  rcSrc.bottom = rcSrc.top + cySrc;
+
+  if((cxDst != cxSrc) || (cyDst != cySrc))
+  {
+    DPRINT1("TransparentBlt() does not support stretching at the moment!\n");
+    goto done;
+  }
+
+  Ret = IntEngTransparentBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+                             DCDest->CombinedClip, XlateObj, &rcDest, &rcSrc,
+                             TransparentColor, 0);
+
+done:
+  DC_UnlockDc(DCSrc);
+  if (BitmapDest)
+  {
+    BITMAPOBJ_UnlockBitmap(BitmapDest);
+  }
+  if (BitmapSrc)
+  {
+    BITMAPOBJ_UnlockBitmap(BitmapSrc);
+  }
+  if(hdcDst != hdcSrc)
+  {
+    DC_UnlockDc(DCDest);
+  }
+  if(XlateObj)
+  {
+    EngDeleteXlate(XlateObj);
+  }
+  return Ret;
+}
+
+/***********************************************************************
+ * MaskBlt
+ * Ported from WINE by sedwards 11-4-03
+ *
+ * Someone thought it would be faster to do it here and then switch back
+ * to GDI32. I dunno. Write a test and let me know.
+ */
+
+static __inline BYTE
+SwapROP3_SrcDst(BYTE bRop3)
+{
+       return (bRop3 & 0x99) | ((bRop3 & 0x22) << 1) | ((bRop3 & 0x44) >> 1);
+}
+
+#define FRGND_ROP3(ROP4)       ((ROP4) & 0x00FFFFFF)
+#define BKGND_ROP3(ROP4)       (ROP3Table[(SwapROP3_SrcDst((ROP4)>>24)) & 0xFF])
+#define DSTCOPY                0x00AA0029
+#define DSTERASE               0x00220326 /* dest = dest & (~src) : DSna */
+
+BOOL STDCALL
+NtGdiMaskBlt (
+       HDC hdcDest, INT nXDest, INT nYDest,
+       INT nWidth, INT nHeight, HDC hdcSrc,
+       INT nXSrc, INT nYSrc, HBITMAP hbmMask,
+       INT xMask, INT yMask, DWORD dwRop,
+       IN DWORD crBackColor)
+{
+       HBITMAP hOldMaskBitmap, hBitmap2, hOldBitmap2, hBitmap3, hOldBitmap3;
+       HDC hDCMask, hDC1, hDC2;
+       static const DWORD ROP3Table[256] =
+       {
+               0x00000042, 0x00010289,
+               0x00020C89, 0x000300AA,
+               0x00040C88, 0x000500A9,
+               0x00060865, 0x000702C5,
+               0x00080F08, 0x00090245,
+               0x000A0329, 0x000B0B2A,
+               0x000C0324, 0x000D0B25,
+               0x000E08A5, 0x000F0001,
+               0x00100C85, 0x001100A6,
+               0x00120868, 0x001302C8,
+               0x00140869, 0x001502C9,
+               0x00165CCA, 0x00171D54,
+               0x00180D59, 0x00191CC8,
+               0x001A06C5, 0x001B0768,
+               0x001C06CA, 0x001D0766,
+               0x001E01A5, 0x001F0385,
+               0x00200F09, 0x00210248,
+               0x00220326, 0x00230B24,
+               0x00240D55, 0x00251CC5,
+               0x002606C8, 0x00271868,
+               0x00280369, 0x002916CA,
+               0x002A0CC9, 0x002B1D58,
+               0x002C0784, 0x002D060A,
+               0x002E064A, 0x002F0E2A,
+               0x0030032A, 0x00310B28,
+               0x00320688, 0x00330008,
+               0x003406C4, 0x00351864,
+               0x003601A8, 0x00370388,
+               0x0038078A, 0x00390604,
+               0x003A0644, 0x003B0E24,
+               0x003C004A, 0x003D18A4,
+               0x003E1B24, 0x003F00EA,
+               0x00400F0A, 0x00410249,
+               0x00420D5D, 0x00431CC4,
+               0x00440328, 0x00450B29,
+               0x004606C6, 0x0047076A,
+               0x00480368, 0x004916C5,
+               0x004A0789, 0x004B0605,
+               0x004C0CC8, 0x004D1954,
+               0x004E0645, 0x004F0E25,
+               0x00500325, 0x00510B26,
+               0x005206C9, 0x00530764,
+               0x005408A9, 0x00550009,
+               0x005601A9, 0x00570389,
+               0x00580785, 0x00590609,
+               0x005A0049, 0x005B18A9,
+               0x005C0649, 0x005D0E29,
+               0x005E1B29, 0x005F00E9,
+               0x00600365, 0x006116C6,
+               0x00620786, 0x00630608,
+               0x00640788, 0x00650606,
+               0x00660046, 0x006718A8,
+               0x006858A6, 0x00690145,
+               0x006A01E9, 0x006B178A,
+               0x006C01E8, 0x006D1785,
+               0x006E1E28, 0x006F0C65,
+               0x00700CC5, 0x00711D5C,
+               0x00720648, 0x00730E28,
+               0x00740646, 0x00750E26,
+               0x00761B28, 0x007700E6,
+               0x007801E5, 0x00791786,
+               0x007A1E29, 0x007B0C68,
+               0x007C1E24, 0x007D0C69,
+               0x007E0955, 0x007F03C9,
+               0x008003E9, 0x00810975,
+               0x00820C49, 0x00831E04,
+               0x00840C48, 0x00851E05,
+               0x008617A6, 0x008701C5,
+               0x008800C6, 0x00891B08,
+               0x008A0E06, 0x008B0666,
+               0x008C0E08, 0x008D0668,
+               0x008E1D7C, 0x008F0CE5,
+               0x00900C45, 0x00911E08,
+               0x009217A9, 0x009301C4,
+               0x009417AA, 0x009501C9,
+               0x00960169, 0x0097588A,
+               0x00981888, 0x00990066,
+               0x009A0709, 0x009B07A8,
+               0x009C0704, 0x009D07A6,
+               0x009E16E6, 0x009F0345,
+               0x00A000C9, 0x00A11B05,
+               0x00A20E09, 0x00A30669,
+               0x00A41885, 0x00A50065,
+               0x00A60706, 0x00A707A5,
+               0x00A803A9, 0x00A90189,
+               0x00AA0029, 0x00AB0889,
+               0x00AC0744, 0x00AD06E9,
+               0x00AE0B06, 0x00AF0229,
+               0x00B00E05, 0x00B10665,
+               0x00B21974, 0x00B30CE8,
+               0x00B4070A, 0x00B507A9,
+               0x00B616E9, 0x00B70348,
+               0x00B8074A, 0x00B906E6,
+               0x00BA0B09, 0x00BB0226,
+               0x00BC1CE4, 0x00BD0D7D,
+               0x00BE0269, 0x00BF08C9,
+               0x00C000CA, 0x00C11B04,
+               0x00C21884, 0x00C3006A,
+               0x00C40E04, 0x00C50664,
+               0x00C60708, 0x00C707AA,
+               0x00C803A8, 0x00C90184,
+               0x00CA0749, 0x00CB06E4,
+               0x00CC0020, 0x00CD0888,
+               0x00CE0B08, 0x00CF0224,
+               0x00D00E0A, 0x00D1066A,
+               0x00D20705, 0x00D307A4,
+               0x00D41D78, 0x00D50CE9,
+               0x00D616EA, 0x00D70349,
+               0x00D80745, 0x00D906E8,
+               0x00DA1CE9, 0x00DB0D75,
+               0x00DC0B04, 0x00DD0228,
+               0x00DE0268, 0x00DF08C8,
+               0x00E003A5, 0x00E10185,
+               0x00E20746, 0x00E306EA,
+               0x00E40748, 0x00E506E5,
+               0x00E61CE8, 0x00E70D79,
+               0x00E81D74, 0x00E95CE6,
+               0x00EA02E9, 0x00EB0849,
+               0x00EC02E8, 0x00ED0848,
+               0x00EE0086, 0x00EF0A08,
+               0x00F00021, 0x00F10885,
+               0x00F20B05, 0x00F3022A,
+               0x00F40B0A, 0x00F50225,
+               0x00F60265, 0x00F708C5,
+               0x00F802E5, 0x00F90845,
+               0x00FA0089, 0x00FB0A09,
+               0x00FC008A, 0x00FD0A0A,
+               0x00FE02A9, 0x00FF0062,
+       };
+
+       if (!hbmMask)
+               return NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0, 0);
+
+       /* 1. make mask bitmap's dc */
+       hDCMask = NtGdiCreateCompatibleDC(hdcDest);
+       hOldMaskBitmap = (HBITMAP)NtGdiSelectBitmap(hDCMask, hbmMask);
+
+       /* 2. make masked Background bitmap */
+
+       /* 2.1 make bitmap */
+       hDC1 = NtGdiCreateCompatibleDC(hdcDest);
+       hBitmap2 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
+       hOldBitmap2 = (HBITMAP)NtGdiSelectBitmap(hDC1, hBitmap2);
+
+       /* 2.2 draw dest bitmap and mask */
+       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, SRCCOPY, 0, 0);
+       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, BKGND_ROP3(dwRop), 0, 0);
+       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, DSTERASE, 0, 0);
+
+       /* 3. make masked Foreground bitmap */
+
+       /* 3.1 make bitmap */
+       hDC2 = NtGdiCreateCompatibleDC(hdcDest);
+       hBitmap3 = NtGdiCreateCompatibleBitmap(hdcDest, nWidth, nHeight);
+       hOldBitmap3 = (HBITMAP)NtGdiSelectBitmap(hDC2, hBitmap3);
+
+       /* 3.2 draw src bitmap and mask */
+       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcDest, nXDest, nYDest, SRCCOPY, 0, 0);
+       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hdcSrc, nXSrc, nYSrc, FRGND_ROP3(dwRop), 0,0);
+       NtGdiBitBlt(hDC2, 0, 0, nWidth, nHeight, hDCMask, xMask, yMask, SRCAND, 0, 0);
+
+       /* 4. combine two bitmap and copy it to hdcDest */
+       NtGdiBitBlt(hDC1, 0, 0, nWidth, nHeight, hDC2, 0, 0, SRCPAINT, 0, 0);
+       NtGdiBitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, hDC1, 0, 0, SRCCOPY, 0, 0);
+
+       /* 5. restore all object */
+       NtGdiSelectBitmap(hDCMask, hOldMaskBitmap);
+       NtGdiSelectBitmap(hDC1, hOldBitmap2);
+       NtGdiSelectBitmap(hDC2, hOldBitmap3);
+
+       /* 6. delete all temp object */
+       NtGdiDeleteObject(hBitmap2);
+       NtGdiDeleteObject(hBitmap3);
+
+       NtGdiDeleteObjectApp(hDC1);
+       NtGdiDeleteObjectApp(hDC2);
+       NtGdiDeleteObjectApp(hDCMask);
+
+       return TRUE;
+}
+
+BOOL
+APIENTRY
+NtGdiPlgBlt(
+    IN HDC hdcTrg,
+    IN LPPOINT pptlTrg,
+    IN HDC hdcSrc,
+    IN INT xSrc,
+    IN INT ySrc,
+    IN INT cxSrc,
+    IN INT cySrc,
+    IN HBITMAP hbmMask,
+    IN INT xMask,
+    IN INT yMask,
+    IN DWORD crBackColor)
+{
+       UNIMPLEMENTED;
+       return FALSE;
+}
+
+BOOL STDCALL
+NtGdiStretchBlt(
+       HDC  hDCDest,
+       INT  XOriginDest,
+       INT  YOriginDest,
+       INT  WidthDest,
+       INT  HeightDest,
+       HDC  hDCSrc,
+       INT  XOriginSrc,
+       INT  YOriginSrc,
+       INT  WidthSrc,
+       INT  HeightSrc,
+       DWORD  ROP,
+       IN DWORD dwBackColor)
+{
+       PDC DCDest = NULL;
+       PDC DCSrc  = NULL;
+       PDC_ATTR Dc_Attr;
+       BITMAPOBJ *BitmapDest, *BitmapSrc;
+       RECTL DestRect;
+       RECTL SourceRect;
+       BOOL Status;
+       XLATEOBJ *XlateObj = NULL;
+       PGDIBRUSHOBJ BrushObj = NULL;
+       BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);
+       BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);
+
+       if (0 == WidthDest || 0 == HeightDest || 0 == WidthSrc || 0 == HeightSrc)
+       {
+               SetLastWin32Error(ERROR_INVALID_PARAMETER);
+               return FALSE;
+       }
+       DCDest = DC_LockDc(hDCDest);
+       if (NULL == DCDest)
+       {
+               DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCDest);
+               SetLastWin32Error(ERROR_INVALID_HANDLE);
+               return FALSE;
+       }
+       if (DCDest->DC_Type == DC_TYPE_INFO)
+       {
+               DC_UnlockDc(DCDest);
+               /* Yes, Windows really returns TRUE in this case */
+               return TRUE;
+       }
+
+       if (UsesSource)
+       {
+               if (hDCSrc != hDCDest)
+               {
+                       DCSrc = DC_LockDc(hDCSrc);
+                       if (NULL == DCSrc)
+                       {
+                               DC_UnlockDc(DCDest);
+                               DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiStretchBlt\n", hDCSrc);
+                               SetLastWin32Error(ERROR_INVALID_HANDLE);
+                               return FALSE;
+                       }
+                       if (DCSrc->DC_Type == DC_TYPE_INFO)
+                       {
+                               DC_UnlockDc(DCSrc);
+                               DC_UnlockDc(DCDest);
+                               /* Yes, Windows really returns TRUE in this case */
+                               return TRUE;
+                       }
+               }
+               else
+               {
+                       DCSrc = DCDest;
+               }
+       }
+       else
+       {
+               DCSrc = NULL;
+       }
+
+       /* Offset the destination and source by the origin of their DCs. */
+       // FIXME: ptlDCOrig is in device coordinates!
+       XOriginDest += DCDest->ptlDCOrig.x;
+       YOriginDest += DCDest->ptlDCOrig.y;
+       if (UsesSource)
+       {
+               XOriginSrc += DCSrc->ptlDCOrig.x;
+               YOriginSrc += DCSrc->ptlDCOrig.y;
+       }
+
+       DestRect.left   = XOriginDest;
+       DestRect.top    = YOriginDest;
+       DestRect.right  = XOriginDest+WidthDest;
+       DestRect.bottom = YOriginDest+HeightDest;
+
+       SourceRect.left   = XOriginSrc;
+       SourceRect.top    = YOriginSrc;
+       SourceRect.right  = XOriginSrc+WidthSrc;
+       SourceRect.bottom = YOriginSrc+HeightSrc;
+
+       /* Determine surfaces to be used in the bitblt */
+       BitmapDest = BITMAPOBJ_LockBitmap(DCDest->w.hBitmap);
+       if (UsesSource)
+       {
+               if (DCSrc->w.hBitmap == DCDest->w.hBitmap)
+                       BitmapSrc = BitmapDest;
+               else
+                       BitmapSrc = BITMAPOBJ_LockBitmap(DCSrc->w.hBitmap);
+
+               int sw = BitmapSrc->SurfObj.sizlBitmap.cx;
+               int sh = BitmapSrc->SurfObj.sizlBitmap.cy;
+               if ( SourceRect.left < 0 )
+               {
+                       DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right)/abs(SourceRect.right-SourceRect.left);
+                       SourceRect.left = 0;
+               }
+               if ( SourceRect.top < 0 )
+               {
+                       DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom)/abs(SourceRect.bottom-SourceRect.top);
+                       SourceRect.top = 0;
+               }
+               if ( SourceRect.right < -1 )
+               {
+                       DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * (-1-SourceRect.left)/abs(SourceRect.right-SourceRect.left);
+                       SourceRect.right = -1;
+               }
+               if ( SourceRect.bottom < -1 )
+               {
+                       DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * (-1-SourceRect.top)/abs(SourceRect.bottom-SourceRect.top);
+                       SourceRect.bottom = -1;
+               }
+               if ( SourceRect.right > sw )
+               {
+                       DestRect.right = DestRect.left + (DestRect.right-DestRect.left) * abs(sw-SourceRect.left) / abs(SourceRect.right-SourceRect.left);
+                       SourceRect.right = sw;
+               }
+               if ( SourceRect.bottom > sh )
+               {
+                       DestRect.bottom = DestRect.top + (DestRect.bottom-DestRect.top) * abs(sh-SourceRect.top) / abs(SourceRect.bottom-SourceRect.top);
+                       SourceRect.bottom = sh;
+               }
+               sw--;
+               sh--;
+               if ( SourceRect.left > sw )
+               {
+                       DestRect.left = DestRect.right - (DestRect.right-DestRect.left) * (SourceRect.right-sw) / abs(SourceRect.right-SourceRect.left);
+                       SourceRect.left = 0;
+               }
+               if ( SourceRect.top > sh )
+               {
+                       DestRect.top = DestRect.bottom - (DestRect.bottom-DestRect.top) * (SourceRect.bottom-sh) / abs(SourceRect.bottom-SourceRect.top);
+                       SourceRect.top = 0;
+               }
+               if (0 == (DestRect.right-DestRect.left) || 0 == (DestRect.bottom-DestRect.top) || 0 == (SourceRect.right-SourceRect.left) || 0 == (SourceRect.bottom-SourceRect.top))
+               {
+                       SetLastWin32Error(ERROR_INVALID_PARAMETER);
+                       Status = FALSE;
+                       goto failed;
+               }
+
+               /* Create the XLATEOBJ. */
+               XlateObj = IntCreateXlateForBlt(DCDest, DCSrc, BitmapDest, BitmapSrc);
+               if (XlateObj == (XLATEOBJ*)-1)
+               {
+                       SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
+                       Status = FALSE;
+                       goto failed;
+               }
+       }
+       else
+       {
+               BitmapSrc = NULL;
+       }
+
+       if (UsesPattern)
+       {
+               Dc_Attr = DCDest->pDc_Attr;
+               if (!Dc_Attr) Dc_Attr = &DCDest->Dc_Attr;
+               BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+               if (NULL == BrushObj)
+               {
+                       SetLastWin32Error(ERROR_INVALID_HANDLE);
+                       Status = FALSE;
+                       goto failed;
+               }
+       }
+       else
+       {
+               BrushObj = NULL;
+       }
+
+       /* Perform the bitblt operation */
+       Status = IntEngStretchBlt(&BitmapDest->SurfObj, &BitmapSrc->SurfObj,
+                                  NULL, DCDest->CombinedClip, XlateObj,
+                                  &DestRect, &SourceRect, NULL, NULL, NULL,
+                                  COLORONCOLOR);
+
+failed:
+       if (XlateObj)
+       {
+               EngDeleteXlate(XlateObj);
+       }
+       if (BrushObj)
+       {
+               BRUSHOBJ_UnlockBrush(BrushObj);
+       }
+       if (UsesSource && DCSrc->w.hBitmap != DCDest->w.hBitmap)
+       {
+               BITMAPOBJ_UnlockBitmap(BitmapSrc);
+       }
+       BITMAPOBJ_UnlockBitmap(BitmapDest);
+       if (UsesSource && hDCSrc != hDCDest)
+       {
+               DC_UnlockDc(DCSrc);
+       }
+       DC_UnlockDc(DCDest);
+
+       return Status;
+}
+
+BOOL FASTCALL
+IntPatBlt(
+   PDC dc,
+   INT XLeft,
+   INT YLeft,
+   INT Width,
+   INT Height,
+   DWORD ROP,
+   PGDIBRUSHOBJ BrushObj)
+{
+   RECTL DestRect;
+   BITMAPOBJ *BitmapObj;
+   GDIBRUSHINST BrushInst;
+   POINTL BrushOrigin;
+   BOOL ret = TRUE;
+
+   ASSERT(BrushObj);
+
+   BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+   if (BitmapObj == NULL)
+   {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+   }
+
+   if (!(BrushObj->flAttrs & GDIBRUSH_IS_NULL))
+   {
+      if (Width > 0)
+      {
+         DestRect.left = XLeft + dc->ptlDCOrig.x;
+         DestRect.right = XLeft + Width + dc->ptlDCOrig.x;
+      }
+      else
+      {
+         DestRect.left = XLeft + Width + 1 + dc->ptlDCOrig.x;
+         DestRect.right = XLeft + dc->ptlDCOrig.x + 1;
+      }
+
+      if (Height > 0)
+      {
+         DestRect.top = YLeft + dc->ptlDCOrig.y;
+         DestRect.bottom = YLeft + Height + dc->ptlDCOrig.y;
+      }
+      else
+      {
+         DestRect.top = YLeft + Height + dc->ptlDCOrig.y + 1;
+         DestRect.bottom = YLeft + dc->ptlDCOrig.y + 1;
+      }
+
+      IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
+
+      BrushOrigin.x = BrushObj->ptOrigin.x + dc->ptlDCOrig.x;
+      BrushOrigin.y = BrushObj->ptOrigin.y + dc->ptlDCOrig.y;
+
+      IntGdiInitBrushInstance(&BrushInst, BrushObj, dc->XlateBrush);
+
+      ret = IntEngBitBlt(
+         &BitmapObj->SurfObj,
+         NULL,
+         NULL,
+         dc->CombinedClip,
+         NULL,
+         &DestRect,
+         NULL,
+         NULL,
+         &BrushInst.BrushObject, // use pDC->eboFill
+         &BrushOrigin,
+         ROP3_TO_ROP4(ROP));
+   }
+
+   BITMAPOBJ_UnlockBitmap(BitmapObj);
+
+   return ret;
+}
+
+BOOL FASTCALL
+IntGdiPolyPatBlt(
+   HDC hDC,
+   DWORD dwRop,
+   PPATRECT pRects,
+   int cRects,
+   ULONG Reserved)
+{
+   int i;
+   PPATRECT r;
+   PGDIBRUSHOBJ BrushObj;
+   DC *dc;
+
+   dc = DC_LockDc(hDC);
+   if (dc == NULL)
+   {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+   }
+   if (dc->DC_Type == DC_TYPE_INFO)
+   {
+      DC_UnlockDc(dc);
+      /* Yes, Windows really returns TRUE in this case */
+      return TRUE;
+   }
+
+   for (r = pRects, i = 0; i < cRects; i++)
+   {
+      BrushObj = BRUSHOBJ_LockBrush(r->hBrush);
+      if(BrushObj != NULL)
+      {
+        IntPatBlt(
+           dc,
+           r->r.left,
+           r->r.top,
+           r->r.right,
+           r->r.bottom,
+           dwRop,
+           BrushObj);
+        BRUSHOBJ_UnlockBrush(BrushObj);
+      }
+      r++;
+   }
+
+   DC_UnlockDc(dc);
+
+   return TRUE;
+}
+
+
+BOOL STDCALL
+NtGdiPatBlt(
+   HDC hDC,
+   INT XLeft,
+   INT YLeft,
+   INT Width,
+   INT Height,
+   DWORD ROP)
+{
+   PGDIBRUSHOBJ BrushObj;
+   DC *dc;
+   PDC_ATTR Dc_Attr;
+   BOOL ret;
+
+   BOOL UsesSource = ROP3_USES_SOURCE(ROP);
+   if (UsesSource)
+   {
+       /* in this case we call on GdiMaskBlt */
+       return NtGdiMaskBlt(hDC, XLeft, YLeft, Width, Height, 0,0,0,0,0,0,ROP,0);
+   }
+
+   dc = DC_LockDc(hDC);
+   if (dc == NULL)
+   {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      return FALSE;
+   }
+   Dc_Attr = dc->pDc_Attr;
+   if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+   if (dc->DC_Type == DC_TYPE_INFO)
+   {
+      DC_UnlockDc(dc);
+      /* Yes, Windows really returns TRUE in this case */
+      return TRUE;
+   }
+
+   BrushObj = BRUSHOBJ_LockBrush(Dc_Attr->hbrush);
+   if (BrushObj == NULL)
+   {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);
+      DC_UnlockDc(dc);
+      return FALSE;
+   }
+
+   ret = IntPatBlt(
+      dc,
+      XLeft,
+      YLeft,
+      Width,
+      Height,
+      ROP,
+      BrushObj);
+
+   BRUSHOBJ_UnlockBrush(BrushObj);
+   DC_UnlockDc(dc);
+
+   return ret;
+}
+
+BOOL STDCALL
+NtGdiPolyPatBlt(
+   HDC hDC,
+   DWORD dwRop,
+   IN PPOLYPATBLT pRects,
+   IN DWORD cRects,
+   IN DWORD Mode)
+{
+   PPATRECT rb = NULL;
+   NTSTATUS Status = STATUS_SUCCESS;
+   BOOL Ret;
+
+   if (cRects > 0)
+   {
+      rb = ExAllocatePoolWithTag(PagedPool, sizeof(PATRECT) * cRects, TAG_PATBLT);
+      if (!rb)
+      {
+         SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+         return FALSE;
+      }
+      _SEH_TRY
+      {
+         ProbeForRead(pRects,
+                      cRects * sizeof(PATRECT),
+                      1);
+         RtlCopyMemory(rb,
+                       pRects,
+                       cRects * sizeof(PATRECT));
+      }
+      _SEH_HANDLE
+      {
+         Status = _SEH_GetExceptionCode();
+      }
+      _SEH_END;
+
+      if (!NT_SUCCESS(Status))
+      {
+         ExFreePool(rb);
+         SetLastNtError(Status);
+         return FALSE;
+      }
+   }
+
+   Ret = IntGdiPolyPatBlt(hDC, dwRop, (PPATRECT)pRects, cRects, Mode);
+
+   if (cRects > 0)
+      ExFreePool(rb);
+
+   return Ret;
+}
index 12b19a3..4a7873e 100644 (file)
@@ -1026,7 +1026,7 @@ IntGdiDeleteDC(HDC hDC, BOOL Force)
   }
 
   /*  Free GDI resources allocated to this DC  */
-  if (!(DCToDelete->DcLevel.flPath & DCPATH_SAVE))
+  if (!(DCToDelete->DcLevel.flPath & DCPATH_SAVESTATE))
   {
     /*
     NtGdiSelectPen (DCHandle, STOCK_BLACK_PEN);
@@ -1054,7 +1054,7 @@ IntGdiDeleteDC(HDC hDC, BOOL Force)
   {
     NtGdiDeleteObject (DCToDelete->w.hGCClipRgn);
   }
-  PATH_DestroyGdiPath (&DCToDelete->w.path);
+  PATH_Delete(DCToDelete->DcLevel.hPath);
 
   DC_UnlockDc( DCToDelete );
   DC_FreeDC ( hDC );
@@ -1326,7 +1326,7 @@ IntGdiCopyToSaveState(PDC dc, PDC newdc)
   nDc_Attr = newdc->pDc_Attr;
   if(!nDc_Attr) nDc_Attr = &newdc->Dc_Attr;
 
-  newdc->DcLevel.flPath     = dc->DcLevel.flPath | DCPATH_SAVE;
+  newdc->DcLevel.flPath     = dc->DcLevel.flPath | DCPATH_SAVESTATE;
   nDc_Attr->dwLayout        = Dc_Attr->dwLayout;
   nDc_Attr->hpen            = Dc_Attr->hpen;
   nDc_Attr->hbrush          = Dc_Attr->hbrush;
@@ -1372,7 +1372,7 @@ IntGdiCopyToSaveState(PDC dc, PDC newdc)
   newdc->DC_Type = dc->DC_Type;
 
 #if 0
-  PATH_InitGdiPath( &newdc->w.path );
+  PATH_InitGdiPath( &newdc->DcLevel.hPath );
 #endif
 
   /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
@@ -1397,7 +1397,7 @@ IntGdiCopyFromSaveState(PDC dc, PDC dcs, HDC hDC)
   sDc_Attr = dcs->pDc_Attr;
   if(!sDc_Attr) sDc_Attr = &dcs->Dc_Attr;
 
-  dc->DcLevel.flPath       = dcs->DcLevel.flPath & ~DCPATH_SAVE;
+  dc->DcLevel.flPath       = dcs->DcLevel.flPath & ~DCPATH_SAVESTATE;
 
   Dc_Attr->dwLayout        = sDc_Attr->dwLayout;
   Dc_Attr->jROP2           = sDc_Attr->jROP2;
@@ -1528,7 +1528,7 @@ IntGdiSetDCState ( HDC hDC, HDC hDCSave )
     dcs = DC_LockDc ( hDCSave );
     if ( dcs )
     {
-      if ( dcs->DcLevel.flPath & DCPATH_SAVE )
+      if ( dcs->DcLevel.flPath & DCPATH_SAVESTATE )
       {
         IntGdiCopyFromSaveState( dc, dcs, dc->DcLevel.hdcSave);
       }
@@ -1824,17 +1824,19 @@ NtGdiRestoreDC(HDC  hDC, INT  SaveLevel)
 
          IntGdiSetDCState(hDC, hdcs);
 
-        if (!PATH_AssignGdiPath( &dc->w.path, &dcs->w.path ))
-        {
-          /* FIXME: This might not be quite right, since we're
-           * returning FALSE but still destroying the saved DC state */
-          success = FALSE;
-        }
          dc = DC_LockDc(hDC);
          if(!dc)
          {
             return FALSE;
          }
+         // Restore Path by removing it, if the Save flag is set.
+         // BeginPath will takecare of the rest.
+         if ( dc->DcLevel.hPath && dc->DcLevel.flPath & DCPATH_SAVE)
+         {
+            PATH_Delete(dc->DcLevel.hPath);
+            dc->DcLevel.hPath = 0;
+            dc->DcLevel.flPath &= ~DCPATH_SAVE;
+         }
        }
        else
        {
@@ -1875,20 +1877,11 @@ NtGdiSaveDC(HDC  hDC)
     return 0;
   }
 
-#if 0
-    /* Copy path. The reason why path saving / restoring is in SaveDC/
-     * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
-     * functions are only in Win16 (which doesn't have paths) and that
-     * SetDCState doesn't allow us to signal an error (which can happen
-     * when copying paths).
-     */
-  if (!PATH_AssignGdiPath (&dcs->w.path, &dc->w.path))
-  {
-    NtGdiDeleteObjectApp (hdcs);
-
-    return 0;
-  }
-#endif
+  /* 
+   * Copy path.
+   */
+  dcs->DcLevel.hPath = dc->DcLevel.hPath;
+  if (dcs->DcLevel.hPath) dcs->DcLevel.flPath |= DCPATH_SAVE;
 
   DC_SetNextDC (dcs, DC_GetNextDC (dc));
   DC_SetNextDC (dc, hdcs);
@@ -2511,6 +2504,10 @@ DC_AllocDC(PUNICODE_STRING Driver)
   Dc_Attr->ulBrushClr = RGB( 255, 255, 255 ); // Do this way too.
   Dc_Attr->crBrushClr = RGB( 255, 255, 255 );
 
+//// This fixes the default brush and pen settings. See DC_InitDC.
+  Dc_Attr->hbrush = NtGdiGetStockObject( WHITE_BRUSH );
+  Dc_Attr->hpen = NtGdiGetStockObject( BLACK_PEN );
+////
   Dc_Attr->hlfntNew = NtGdiGetStockObject(SYSTEM_FONT);
   TextIntRealizeFont(Dc_Attr->hlfntNew);
 
@@ -2536,8 +2533,10 @@ DC_InitDC(HDC  DCHandle)
 {
 //  NtGdiRealizeDefaultPalette(DCHandle);
 
-  NtGdiSelectBrush(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
-  NtGdiSelectPen(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
+////  Removed for now.. See above brush and pen.
+//  NtGdiSelectBrush(DCHandle, NtGdiGetStockObject( WHITE_BRUSH ));
+//  NtGdiSelectPen(DCHandle, NtGdiGetStockObject( BLACK_PEN ));
+////
   //NtGdiSelectFont(DCHandle, hFont);
 
 /*
@@ -2729,6 +2728,10 @@ DC_SetOwnership(HDC hDC, PEPROCESS Owner)
         {
             if(!GDIOBJ_SetOwnership(pDC->w.hGCClipRgn, Owner)) return FALSE;
         }
+        if (pDC->DcLevel.hPath)
+        {
+           if(!GDIOBJ_SetOwnership(pDC->DcLevel.hPath, Owner)) return FALSE;
+        }
         DC_UnlockDc(pDC);
     }
     return TRUE;
index 6c533df..f7129b1 100644 (file)
@@ -77,7 +77,7 @@ IntGdiPolygon(PDC    dc,
         UnsafePoints[CurrentPoint].y += dc->ptlDCOrig.y;
     }
 
-    if (PATH_IsPathOpen(dc->w.path))
+    if (PATH_IsPathOpen(dc->DcLevel))
         ret = PATH_Polygon(dc, UnsafePoints, Count );
     else
     {
@@ -632,7 +632,7 @@ IntRectangle(PDC dc,
     Dc_Attr = dc->pDc_Attr;
     if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-    if ( PATH_IsPathOpen(dc->w.path) )
+    if ( PATH_IsPathOpen(dc->DcLevel) )
     {
         ret = PATH_Rectangle ( dc, LeftRect, TopRect, RightRect, BottomRect );
     }
@@ -789,7 +789,7 @@ IntRoundRect(
 
     ASSERT ( dc ); // caller's responsibility to set this up
 
-    if ( PATH_IsPathOpen(dc->w.path) )
+    if ( PATH_IsPathOpen(dc->DcLevel) )
         return PATH_RoundRect ( dc, left, top, right, bottom,
                                 xCurveDiameter, yCurveDiameter );
     Dc_Attr = dc->pDc_Attr;
index 199b34d..aba8820 100644 (file)
@@ -55,7 +55,7 @@ IntGdiMoveToEx(DC      *dc,
     CoordLPtoDP(dc, &Dc_Attr->ptfxCurrent); // Update fx
     Dc_Attr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
 
-    PathIsOpen = PATH_IsPathOpen(dc->w.path);
+    PathIsOpen = PATH_IsPathOpen(dc->DcLevel);
 
     if ( PathIsOpen )
         return PATH_MoveTo ( dc );
@@ -99,9 +99,10 @@ IntGdiLineTo(DC  *dc,
 
     if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-    if (PATH_IsPathOpen(dc->w.path))
+    if (PATH_IsPathOpen(dc->DcLevel))
     {
         Ret = PATH_LineTo(dc, XEnd, YEnd);
+#if 0
         if (Ret)
         {
             // FIXME - PATH_LineTo should maybe do this...
@@ -111,6 +112,7 @@ IntGdiLineTo(DC  *dc,
             CoordLPtoDP(dc, &Dc_Attr->ptfxCurrent); // Update fx
             Dc_Attr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
         }
+#endif
         return Ret;
     }
     else
@@ -184,7 +186,7 @@ IntGdiPolyBezier(DC      *dc,
 {
     BOOL ret = FALSE; // default to FAILURE
 
-    if ( PATH_IsPathOpen(dc->w.path) )
+    if ( PATH_IsPathOpen(dc->DcLevel) )
     {
         return PATH_PolyBezier ( dc, pt, Count );
     }
@@ -214,7 +216,7 @@ IntGdiPolyBezierTo(DC      *dc,
     PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
     if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-    if ( PATH_IsPathOpen(dc->w.path) )
+    if ( PATH_IsPathOpen(dc->DcLevel) )
         ret = PATH_PolyBezierTo ( dc, pt, Count );
     else /* We'll do it using PolyBezier */
     {
@@ -257,7 +259,7 @@ IntGdiPolyline(DC      *dc,
     PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
     if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-    if (PATH_IsPathOpen(dc->w.path))
+    if (PATH_IsPathOpen(dc->DcLevel))
         return PATH_Polyline(dc, pt, Count);
 
     /* Get BRUSHOBJ from current pen. */
@@ -316,7 +318,7 @@ IntGdiPolylineTo(DC      *dc,
     PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
     if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-    if (PATH_IsPathOpen(dc->w.path))
+    if (PATH_IsPathOpen(dc->DcLevel))
     {
         ret = PATH_PolylineTo(dc, pt, Count);
     }
@@ -412,6 +414,7 @@ NtGdiPolyDraw(
     IN ULONG cCount)
 {
     PDC dc;
+    PPATH pPath;
     BOOL result = FALSE;
     POINT lastmove;
     unsigned int i;
@@ -466,9 +469,14 @@ NtGdiPolyDraw(
 
             if ( lpbTypes[i] & PT_CLOSEFIGURE )
             {
-                if ( PATH_IsPathOpen(dc->w.path) )
+                if ( PATH_IsPathOpen(dc->DcLevel) )
                 {
-                    IntGdiCloseFigure( dc );
+                    pPath = PATH_LockPath( dc->DcLevel.hPath );
+                    if (pPath)
+                    {
+                       IntGdiCloseFigure( pPath );
+                       PATH_UnlockPath( pPath );
+                    }
                 }
                 else IntGdiLineTo( dc, lastmove.x, lastmove.y );
             }
index 21de3bf..fff456e 100644 (file)
@@ -16,7 +16,6 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id$ */
 
 #include <w32k.h>
 #include "math.h"
 #define GROW_FACTOR_NUMER    2  /* Numerator of grow factor for the array */
 #define GROW_FACTOR_DENOM    1  /* Denominator of grow factor             */
 
-BOOL FASTCALL PATH_AddEntry (GdiPath *pPath, const POINT *pPoint, BYTE flags);
-BOOL FASTCALL PATH_AddFlatBezier (GdiPath *pPath, POINT *pt, BOOL closed);
-BOOL FASTCALL PATH_DoArcPart (GdiPath *pPath, FLOAT_POINT corners[], double angleStart, double angleEnd, BOOL addMoveTo);
-BOOL FASTCALL PATH_FillPath( PDC dc, GdiPath *pPath );
-BOOL FASTCALL PATH_FlattenPath (GdiPath *pPath);
+BOOL FASTCALL PATH_AddEntry (PPATH pPath, const POINT *pPoint, BYTE flags);
+BOOL FASTCALL PATH_AddFlatBezier (PPATH pPath, POINT *pt, BOOL closed);
+BOOL FASTCALL PATH_DoArcPart (PPATH pPath, FLOAT_POINT corners[], double angleStart, double angleEnd, BYTE startEntryType);
+BOOL FASTCALL PATH_FillPath( PDC dc, PPATH pPath );
+BOOL FASTCALL PATH_FlattenPath (PPATH pPath);
 VOID FASTCALL PATH_NormalizePoint (FLOAT_POINT corners[], const FLOAT_POINT *pPoint, double *pX, double *pY);
-BOOL FASTCALL PATH_PathToRegion (GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn);
-BOOL FASTCALL PATH_ReserveEntries (GdiPath *pPath, INT numEntries);
+
+BOOL FASTCALL PATH_ReserveEntries (PPATH pPath, INT numEntries);
 VOID FASTCALL PATH_ScaleNormalizedPoint (FLOAT_POINT corners[], double x, double y, POINT *pPoint);
-BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath);
+BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath);
 BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2);
 
-VOID FASTCALL
-IntGetCurrentPositionEx(PDC dc, LPPOINT pt);
+VOID FASTCALL IntGetCurrentPositionEx(PDC dc, LPPOINT pt);
 
+/***********************************************************************
+ * Internal functions
+ */
 
 BOOL
-STDCALL
-NtGdiAbortPath(HDC  hDC)
+FASTCALL
+PATH_Delete(HPATH hPath)
 {
-  BOOL ret = TRUE;
-  PDC dc = DC_LockDc ( hDC );
-
-  if( !dc ) return FALSE;
-
-  PATH_EmptyPath(&dc->w.path);
-
-  DC_UnlockDc ( dc );
-  return ret;
+  if (!hPath) return FALSE;
+  PPATH pPath = PATH_LockPath( hPath );
+  if (!pPath) return FALSE;
+  PATH_DestroyGdiPath( pPath );
+  PATH_UnlockPath( pPath );
+  PATH_FreeExtPathByHandle(hPath);
+  return TRUE;
 }
 
-BOOL
-STDCALL
-NtGdiBeginPath( HDC  hDC )
-{
-  BOOL ret = TRUE;
-  PDC dc = DC_LockDc ( hDC );
-
-  if( !dc ) return FALSE;
-
-  /* If path is already open, do nothing */
-  if ( dc->w.path.state != PATH_Open )
-  {
-    /* Make sure that path is empty */
-    PATH_EmptyPath( &dc->w.path );
-
-    /* Initialize variables for new path */
-    dc->w.path.newStroke = TRUE;
-    dc->w.path.state = PATH_Open;
-  }
-
-  DC_UnlockDc ( dc );
-  return ret;
-}
 
 VOID
 FASTCALL
-IntGdiCloseFigure(PDC pDc)
+IntGdiCloseFigure(PPATH pPath)
 {
-   ASSERT(pDc);
-   ASSERT(pDc->w.path.state == PATH_Open);
+   ASSERT(pPath->state == PATH_Open);
 
    // FIXME: Shouldn't we draw a line to the beginning of the figure?
    // Set PT_CLOSEFIGURE on the last entry and start a new stroke
-   if(pDc->w.path.numEntriesUsed)
+   if(pPath->numEntriesUsed)
    {
-      pDc->w.path.pFlags[pDc->w.path.numEntriesUsed-1]|=PT_CLOSEFIGURE;
-      pDc->w.path.newStroke=TRUE;
+      pPath->pFlags[pPath->numEntriesUsed-1]|=PT_CLOSEFIGURE;
+      pPath->newStroke=TRUE;
    }
 }
 
+/* PATH_FillPath
+ *
+ *
+ */
 BOOL
-STDCALL
-NtGdiCloseFigure(HDC hDC)
+FASTCALL
+PATH_FillPath( PDC dc, PPATH pPath )
 {
-   BOOL Ret = FALSE; // default to failure
-   PDC pDc;
+  INT   mapMode, graphicsMode;
+  SIZE  ptViewportExt, ptWindowExt;
+  POINTL ptViewportOrg, ptWindowOrg;
+  XFORM xform;
+  HRGN  hrgn;
+  PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
-   DPRINT("Enter %s\n", __FUNCTION__);
+  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-   pDc = DC_LockDc(hDC);
-   if(!pDc) return FALSE;
+  if( pPath->state != PATH_Closed )
+  {
+    SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+    return FALSE;
+  }
 
-   if(pDc->w.path.state==PATH_Open)
-   {
-      IntGdiCloseFigure(pDc);
-      Ret = TRUE;
-   }
-   else
-   {
-      // FIXME: check if lasterror is set correctly
-      SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
-   }
+  if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgn ))
+  {
+    /* Since PaintRgn interprets the region as being in logical coordinates
+     * but the points we store for the path are already in device
+     * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
+     * Using SaveDC to save information about the mapping mode / world
+     * transform would be easier but would require more overhead, especially
+     * now that SaveDC saves the current path.
+     */
 
-   DC_UnlockDc(pDc);
+    /* Save the information about the old mapping mode */
+    mapMode = Dc_Attr->iMapMode;
+    ptViewportExt = Dc_Attr->szlViewportExt;
+    ptViewportOrg = Dc_Attr->ptlViewportOrg;
+    ptWindowExt   = Dc_Attr->szlWindowExt;
+    ptWindowOrg   = Dc_Attr->ptlWindowOrg;
 
-   return Ret;
-}
+    /* Save world transform
+     * NB: The Windows documentation on world transforms would lead one to
+     * believe that this has to be done only in GM_ADVANCED; however, my
+     * tests show that resetting the graphics mode to GM_COMPATIBLE does
+     * not reset the world transform.
+     */
+    xform = dc->DcLevel.xformWorld2Wnd;
 
-BOOL
-STDCALL
-NtGdiEndPath(HDC  hDC)
-{
-  BOOL ret = TRUE;
-  PDC dc = DC_LockDc ( hDC );
+    /* Set MM_TEXT */
+    IntGdiSetMapMode( dc, MM_TEXT );
+    Dc_Attr->ptlViewportOrg.x = 0;
+    Dc_Attr->ptlViewportOrg.y = 0;
+    Dc_Attr->ptlWindowOrg.x = 0;
+    Dc_Attr->ptlWindowOrg.y = 0;
+
+    graphicsMode = Dc_Attr->iGraphicsMode;
+    Dc_Attr->iGraphicsMode = GM_ADVANCED;
+    IntGdiModifyWorldTransform( dc, &xform, MWT_IDENTITY );
+    Dc_Attr->iGraphicsMode =  graphicsMode;
 
-  if ( !dc ) return FALSE;
+    /* Paint the region */
+    IntGdiPaintRgn( dc, hrgn );
+    NtGdiDeleteObject( hrgn );
+    /* Restore the old mapping mode */
+    IntGdiSetMapMode( dc, mapMode );
+    Dc_Attr->szlViewportExt = ptViewportExt;
+    Dc_Attr->ptlViewportOrg = ptViewportOrg;
+    Dc_Attr->szlWindowExt   = ptWindowExt;
+    Dc_Attr->ptlWindowOrg   = ptWindowOrg;
 
-  /* Check that path is currently being constructed */
-  if( dc->w.path.state != PATH_Open )
-  {
-    ret = FALSE;
+    /* Go to GM_ADVANCED temporarily to restore the world transform */
+    graphicsMode = Dc_Attr->iGraphicsMode;
+    Dc_Attr->iGraphicsMode = GM_ADVANCED;
+    IntGdiModifyWorldTransform( dc, &xform, MWT_MAX+1 );
+    Dc_Attr->iGraphicsMode = graphicsMode;
+    return TRUE;
   }
-  /* Set flag to indicate that path is finished */
-  else dc->w.path.state = PATH_Closed;
-
-  DC_UnlockDc ( dc );
-  return ret;
+  return FALSE;
 }
 
-BOOL
-STDCALL
-NtGdiFillPath(HDC  hDC)
+/* PATH_InitGdiPath
+ *
+ * Initializes the GdiPath structure.
+ */
+VOID
+FASTCALL
+PATH_InitGdiPath ( PPATH pPath )
 {
-  BOOL ret = TRUE;
-  PDC dc = DC_LockDc ( hDC );
+  ASSERT(pPath!=NULL);
 
-  if ( !dc ) return FALSE;
+  pPath->state=PATH_Null;
+  pPath->pPoints=NULL;
+  pPath->pFlags=NULL;
+  pPath->numEntriesUsed=0;
+  pPath->numEntriesAllocated=0;
+}
 
-  ret = PATH_FillPath( dc, &dc->w.path );
-  if( ret )
-  {
-    /* FIXME: Should the path be emptied even if conversion
-       failed? */
-    PATH_EmptyPath( &dc->w.path );
-  }
+/* PATH_DestroyGdiPath
+ *
+ * Destroys a GdiPath structure (frees the memory in the arrays).
+ */
+VOID
+FASTCALL
+PATH_DestroyGdiPath ( PPATH pPath )
+{
+  ASSERT(pPath!=NULL);
 
-  DC_UnlockDc ( dc );
-  return ret;
+  if (pPath->pPoints) ExFreePool(pPath->pPoints);
+  if (pPath->pFlags) ExFreePool(pPath->pFlags);
 }
 
+/* PATH_AssignGdiPath
+ *
+ * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
+ * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
+ * not just the pointers. Since this means that the arrays in pPathDest may
+ * need to be resized, pPathDest should have been initialized using
+ * PATH_InitGdiPath (in C++, this function would be an assignment operator,
+ * not a copy constructor).
+ * Returns TRUE if successful, else FALSE.
+ */
 BOOL
-STDCALL
-NtGdiFlattenPath(HDC  hDC)
+FASTCALL
+PATH_AssignGdiPath ( PPATH pPathDest, const PPATH pPathSrc )
 {
-    BOOL Ret = FALSE;
-    DC *pDc;
-
-    DPRINT("Enter %s\n", __FUNCTION__);
+  ASSERT(pPathDest!=NULL && pPathSrc!=NULL);
 
-    pDc = DC_LockDc(hDC);
-    if(!pDc) return FALSE;
+  /* Make sure destination arrays are big enough */
+  if ( !PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed) )
+    return FALSE;
 
-    if(pDc->w.path.state == PATH_Open)
-           Ret = PATH_FlattenPath(&pDc->w.path);
+  /* Perform the copy operation */
+  memcpy(pPathDest->pPoints, pPathSrc->pPoints,
+    sizeof(POINT)*pPathSrc->numEntriesUsed);
+  memcpy(pPathDest->pFlags, pPathSrc->pFlags,
+    sizeof(BYTE)*pPathSrc->numEntriesUsed);
 
-    DC_UnlockDc(pDc);
-    return Ret;
+  pPathDest->state=pPathSrc->state;
+  pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
+  pPathDest->newStroke=pPathSrc->newStroke;
+  return TRUE;
 }
 
-
+/* PATH_MoveTo
+ *
+ * Should be called when a MoveTo is performed on a DC that has an
+ * open path. This starts a new stroke. Returns TRUE if successful, else
+ * FALSE.
+ */
 BOOL
-APIENTRY
-NtGdiGetMiterLimit(
-    IN HDC hdc,
-    OUT PDWORD pdwOut)
+FASTCALL
+PATH_MoveTo ( PDC dc )
 {
-  DC *pDc;
-  gxf_long worker;
-  NTSTATUS Status = STATUS_SUCCESS;
-
-  if(!(pDc = DC_LockDc(hdc))) return FALSE;
-
-  worker.f = pDc->DcLevel.laPath.eMiterLimit;
+  PPATH pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-  if (pdwOut)
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
   {
-      _SEH_TRY
-      {
-          ProbeForWrite(pdwOut,
-                 sizeof(DWORD),
-                             1);
-          *pdwOut = worker.l;
-      }
-      _SEH_HANDLE
-      {
-          Status = _SEH_GetExceptionCode();
-      }
-       _SEH_END;
-      if (!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         DC_UnlockDc(pDc);
-         return FALSE;
-      }
+    PATH_UnlockPath( pPath );
+    /* FIXME: Do we have to call SetLastError? */
+    return FALSE;
   }
-
-  DC_UnlockDc(pDc);
+  /* Start a new stroke */
+  pPath->newStroke = TRUE;
+  PATH_UnlockPath( pPath );
   return TRUE;
-
 }
 
-INT
-STDCALL
-NtGdiGetPath(
-   HDC hDC,
-   LPPOINT Points,
-   LPBYTE Types,
-   INT nSize)
+/* PATH_LineTo
+ *
+ * Should be called when a LineTo is performed on a DC that has an
+ * open path. This adds a PT_LINETO entry to the path (and possibly
+ * a PT_MOVETO entry, if this is the first LineTo in a stroke).
+ * Returns TRUE if successful, else FALSE.
+ */
+BOOL
+FASTCALL
+PATH_LineTo ( PDC dc, INT x, INT y )
 {
-   INT ret = -1;
-   GdiPath *pPath;
-
-   DC *dc = DC_LockDc(hDC);
-   if(!dc)
-   {
-      DPRINT1("Can't lock dc!\n");
-      return -1;
-   }
+  BOOL Ret;
+  PPATH pPath;
+  POINT point, pointCurPos;
 
-   pPath = &dc->w.path;
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-   if(pPath->state != PATH_Closed)
-   {
-      SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
-      goto done;
-   }
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
-   if(nSize==0)
-   {
-      ret = pPath->numEntriesUsed;
-   }
-   else if(nSize<pPath->numEntriesUsed)
-   {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      goto done;
-   }
-   else
-   {
-      _SEH_TRY
-      {
-         memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
-         memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
-
-         /* Convert the points to logical coordinates */
-         IntDPtoLP(dc, Points, pPath->numEntriesUsed);
+  /* Convert point to device coordinates */
+  point.x=x;
+  point.y=y;
+  CoordLPtoDP ( dc, &point );
 
-         ret = pPath->numEntriesUsed;
-      }
-      _SEH_HANDLE
-      {
-         SetLastNtError(_SEH_GetExceptionCode());
-      }
-      _SEH_END
-   }
+  /* Add a PT_MOVETO if necessary */
+  if ( pPath->newStroke )
+  {
+    pPath->newStroke = FALSE;
+    IntGetCurrentPositionEx ( dc, &pointCurPos );
+    CoordLPtoDP ( dc, &pointCurPos );
+    if ( !PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO) )
+    {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+    }
+  }
 
-done:
-   DC_UnlockDc(dc);
-   return ret;
+  /* Add a PT_LINETO entry */
+  Ret = PATH_AddEntry(pPath, &point, PT_LINETO);
+  PATH_UnlockPath( pPath );
+  return Ret;
 }
 
-HRGN
-STDCALL
-NtGdiPathToRegion(HDC  hDC)
+/* PATH_Rectangle
+ *
+ * Should be called when a call to Rectangle is performed on a DC that has
+ * an open path. Returns TRUE if successful, else FALSE.
+ */
+BOOL
+FASTCALL
+PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
 {
-   GdiPath *pPath;
-   HRGN  hrgnRval = 0;
-   DC *pDc;
-   PDC_ATTR Dc_Attr;
-
-   DPRINT("Enter %s\n", __FUNCTION__);
+  PPATH pPath;
+  POINT corners[2], pointTemp;
+  INT   temp;
 
-   pDc = DC_LockDc(hDC);
-   if(!pDc) return NULL;
-   Dc_Attr = pDc->pDc_Attr;
-   if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
-   pPath = &pDc->w.path;
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-   if(pPath->state!=PATH_Closed)
-   {
-      //FIXME: check that setlasterror is being called correctly
-      SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
-   }
-   else
-   {
-      /* FIXME: Should we empty the path even if conversion failed? */
-      if(PATH_PathToRegion(pPath, Dc_Attr->jFillMode, &hrgnRval))
-           PATH_EmptyPath(pPath);
-   }
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
-   DC_UnlockDc(pDc);
-   return hrgnRval;
-}
+  /* Convert points to device coordinates */
+  corners[0].x=x1;
+  corners[0].y=y1;
+  corners[1].x=x2;
+  corners[1].y=y2;
+  IntLPtoDP ( dc, corners, 2 );
 
-BOOL
-APIENTRY
-NtGdiSetMiterLimit(
-    IN HDC hdc,
-    IN DWORD dwNew,
-    IN OUT OPTIONAL PDWORD pdwOut)
-{
-  DC *pDc;
-  gxf_long worker, worker1;
-  NTSTATUS Status = STATUS_SUCCESS;
+  /* Make sure first corner is top left and second corner is bottom right */
+  if ( corners[0].x > corners[1].x )
+  {
+    temp=corners[0].x;
+    corners[0].x=corners[1].x;
+    corners[1].x=temp;
+  }
+  if ( corners[0].y > corners[1].y )
+  {
+    temp=corners[0].y;
+    corners[0].y=corners[1].y;
+    corners[1].y=temp;
+  }
 
-  if(!(pDc = DC_LockDc(hdc))) return FALSE;
+  /* In GM_COMPATIBLE, don't include bottom and right edges */
+  if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+  {
+    corners[1].x--;
+    corners[1].y--;
+  }
 
-  worker.l  = dwNew;
-  worker1.f = pDc->DcLevel.laPath.eMiterLimit;
-  pDc->DcLevel.laPath.eMiterLimit = worker.f;
+  /* Close any previous figure */
+  IntGdiCloseFigure(pPath);
 
-  if (pdwOut)
+  /* Add four points to the path */
+  pointTemp.x=corners[1].x;
+  pointTemp.y=corners[0].y;
+  if ( !PATH_AddEntry(pPath, &pointTemp, PT_MOVETO) )
   {
-      _SEH_TRY
-      {
-          ProbeForWrite(pdwOut,
-                 sizeof(DWORD),
-                             1);
-          *pdwOut = worker1.l;
-      }
-      _SEH_HANDLE
-      {
-          Status = _SEH_GetExceptionCode();
-      }
-       _SEH_END;
-      if (!NT_SUCCESS(Status))
-      {
-         SetLastNtError(Status);
-         DC_UnlockDc(pDc);
-         return FALSE;
-      }
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
+  if ( !PATH_AddEntry(pPath, corners, PT_LINETO) )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
+  pointTemp.x=corners[0].x;
+  pointTemp.y=corners[1].y;
+  if ( !PATH_AddEntry(pPath, &pointTemp, PT_LINETO) )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
+  if ( !PATH_AddEntry(pPath, corners+1, PT_LINETO) )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
   }
 
-  DC_UnlockDc(pDc);
+  /* Close the rectangle figure */
+  IntGdiCloseFigure(pPath) ;
+  PATH_UnlockPath( pPath );
   return TRUE;
 }
 
-BOOL
-STDCALL
-NtGdiStrokeAndFillPath(HDC hDC)
+/* PATH_RoundRect
+ *
+ * Should be called when a call to RoundRect is performed on a DC that has
+ * an open path. Returns TRUE if successful, else FALSE.
+ *
+ * FIXME: it adds the same entries to the path as windows does, but there
+ * is an error in the bezier drawing code so that there are small pixel-size
+ * gaps when the resulting path is drawn by StrokePath()
+ */
+BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
 {
-   DC *pDc;
-   BOOL bRet = FALSE;
+   PPATH pPath;
+   POINT corners[2], pointTemp;
+   FLOAT_POINT ellCorners[2];
 
-   DPRINT("Enter %s\n", __FUNCTION__);
+   pPath = PATH_LockPath( dc->DcLevel.hPath );
+   if (!pPath) return FALSE;   
 
-   if(!(pDc = DC_LockDc(hDC))) return FALSE;
+   /* Check that path is open */
+   if(pPath->state!=PATH_Open)
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
 
-   bRet = PATH_FillPath(pDc, &pDc->w.path);
-   if(bRet) bRet = PATH_StrokePath(pDc, &pDc->w.path);
-   if(bRet) PATH_EmptyPath(&pDc->w.path);
+   if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
 
-   DC_UnlockDc(pDc);
-   return bRet;
+   /* Add points to the roundrect path */
+   ellCorners[0].x = corners[1].x-ell_width;
+   ellCorners[0].y = corners[0].y;
+   ellCorners[1].x = corners[1].x;
+   ellCorners[1].y = corners[0].y+ell_height;
+   if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, PT_MOVETO))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   pointTemp.x = corners[0].x+ell_width/2;
+   pointTemp.y = corners[0].y;
+   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   ellCorners[0].x = corners[0].x;
+   ellCorners[1].x = corners[0].x+ell_width;
+   if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   pointTemp.x = corners[0].x;
+   pointTemp.y = corners[1].y-ell_height/2;
+   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   ellCorners[0].y = corners[1].y-ell_height;
+   ellCorners[1].y = corners[1].y;
+   if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   pointTemp.x = corners[1].x-ell_width/2;
+   pointTemp.y = corners[1].y;
+   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+   ellCorners[0].x = corners[1].x-ell_width;
+   ellCorners[1].x = corners[1].x;
+   if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
+   {
+      PATH_UnlockPath( pPath );
+      return FALSE;
+   }
+
+   IntGdiCloseFigure(pPath);
+   PATH_UnlockPath( pPath );
+   return TRUE;
 }
 
+/* PATH_Ellipse
+ *
+ * Should be called when a call to Ellipse is performed on a DC that has
+ * an open path. This adds four Bezier splines representing the ellipse
+ * to the path. Returns TRUE if successful, else FALSE.
+ */
 BOOL
-STDCALL
-NtGdiStrokePath(HDC hDC)
+FASTCALL
+PATH_Ellipse ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
 {
-    DC *pDc;
-    BOOL bRet = FALSE;
-
-    DPRINT("Enter %s\n", __FUNCTION__);
-
-    if(!(pDc = DC_LockDc(hDC))) return FALSE;
-
-    bRet = PATH_StrokePath(pDc, &pDc->w.path);
-    PATH_EmptyPath(&pDc->w.path);
-
-    DC_UnlockDc(pDc);
-    return bRet;
+  PPATH pPath;
+  /* TODO: This should probably be revised to call PATH_AngleArc */
+  /* (once it exists) */
+  BOOL Ret = PATH_Arc ( dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2, GdiTypeArc );
+  if (Ret)
+  {
+     pPath = PATH_LockPath( dc->DcLevel.hPath );
+     if (!pPath) return FALSE;
+     IntGdiCloseFigure(pPath);
+     PATH_UnlockPath( pPath );
+  }
+  return Ret;
 }
 
+/* PATH_Arc
+ *
+ * Should be called when a call to Arc is performed on a DC that has
+ * an open path. This adds up to five Bezier splines representing the arc
+ * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
+ * when 'lines' is 2, we add 2 extra lines to get a pie, and when 'lines' is
+ * -1 we add 1 extra line from the current DC position to the starting position
+ * of the arc before drawing the arc itself (arcto). Returns TRUE if successful,
+ * else FALSE.
+ */
 BOOL
-STDCALL
-NtGdiWidenPath(HDC  hDC)
+FASTCALL
+PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
+   INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines)
 {
-   UNIMPLEMENTED;
-   return FALSE;
-}
+  double  angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
+          /* Initialize angleEndQuadrant to silence gcc's warning */
+  double  x, y;
+  FLOAT_POINT corners[2], pointStart, pointEnd;
+  POINT   centre, pointCurPos;
+  BOOL    start, end, Ret = TRUE;
+  INT     temp;
+  BOOL    clockwise;
+  PPATH   pPath;
 
-BOOL STDCALL NtGdiSelectClipPath(HDC  hDC,
-                         int  Mode)
-{
- HRGN  hrgnPath;
- BOOL  success = FALSE;
- PDC dc = DC_LockDc ( hDC );
- PDC_ATTR Dc_Attr;
- if( !dc ) return FALSE;
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- /* Check that path is closed */
- if( dc->w.path.state != PATH_Closed )
- {
-   SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
-   return FALSE;
- }
- /* Construct a region from the path */
- else if( PATH_PathToRegion( &dc->w.path, Dc_Attr->jFillMode, &hrgnPath ) )
- {
-   success = GdiExtSelectClipRgn( dc, hrgnPath, Mode ) != ERROR;
-   NtGdiDeleteObject( hrgnPath );
-
-   /* Empty the path */
-   if( success )
-     PATH_EmptyPath( &dc->w.path);
-   /* FIXME: Should this function delete the path even if it failed? */
- }
+  /* FIXME: This function should check for all possible error returns */
+  /* FIXME: Do we have to respect newStroke? */
 
- DC_UnlockDc ( dc );
- return success;
-}
+  ASSERT ( dc );
 
-/***********************************************************************
- * Exported functions
- */
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
+  clockwise = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
 
-/* PATH_FillPath
- *
- *
- */
-BOOL
-FASTCALL
-PATH_FillPath( PDC dc, GdiPath *pPath )
-{
-  INT   mapMode, graphicsMode;
-  SIZE  ptViewportExt, ptWindowExt;
-  POINTL ptViewportOrg, ptWindowOrg;
-  XFORM xform;
-  HRGN  hrgn;
-  PDC_ATTR Dc_Attr = dc->pDc_Attr;
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    Ret = FALSE;
+    goto ArcExit;    
+  }
 
-  if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+  /* Check for zero height / width */
+  /* FIXME: Only in GM_COMPATIBLE? */
+  if ( x1==x2 || y1==y2 )
+  {
+    Ret = TRUE;
+    goto ArcExit;
+  }
+  /* Convert points to device coordinates */
+  corners[0].x=(FLOAT)x1;
+  corners[0].y=(FLOAT)y1;
+  corners[1].x=(FLOAT)x2;
+  corners[1].y=(FLOAT)y2;
+  pointStart.x=(FLOAT)xStart;
+  pointStart.y=(FLOAT)yStart;
+  pointEnd.x=(FLOAT)xEnd;
+  pointEnd.y=(FLOAT)yEnd;
+  INTERNAL_LPTODP_FLOAT(dc, corners);
+  INTERNAL_LPTODP_FLOAT(dc, corners+1);
+  INTERNAL_LPTODP_FLOAT(dc, &pointStart);
+  INTERNAL_LPTODP_FLOAT(dc, &pointEnd);
 
-  if( pPath->state != PATH_Closed )
+  /* Make sure first corner is top left and second corner is bottom right */
+  if ( corners[0].x > corners[1].x )
   {
-    SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
-    return FALSE;
+    temp=corners[0].x;
+    corners[0].x=corners[1].x;
+    corners[1].x=temp;
+  }
+  if ( corners[0].y > corners[1].y )
+  {
+    temp=corners[0].y;
+    corners[0].y=corners[1].y;
+    corners[1].y=temp;
   }
 
-  if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgn ))
+  /* Compute start and end angle */
+  PATH_NormalizePoint(corners, &pointStart, &x, &y);
+  angleStart=atan2(y, x);
+  PATH_NormalizePoint(corners, &pointEnd, &x, &y);
+  angleEnd=atan2(y, x);
+
+  /* Make sure the end angle is "on the right side" of the start angle */
+  if ( clockwise )
   {
-    /* Since PaintRgn interprets the region as being in logical coordinates
-     * but the points we store for the path are already in device
-     * coordinates, we have to set the mapping mode to MM_TEXT temporarily.
-     * Using SaveDC to save information about the mapping mode / world
-     * transform would be easier but would require more overhead, especially
-     * now that SaveDC saves the current path.
-     */
+    if ( angleEnd <= angleStart )
+    {
+      angleEnd+=2*M_PI;
+      ASSERT(angleEnd>=angleStart);
+    }
+  }
+  else
+  {
+    if(angleEnd>=angleStart)
+    {
+      angleEnd-=2*M_PI;
+      ASSERT(angleEnd<=angleStart);
+    }
+  }
 
-    /* Save the information about the old mapping mode */
-    mapMode = Dc_Attr->iMapMode;
-    ptViewportExt = Dc_Attr->szlViewportExt;
-    ptViewportOrg = Dc_Attr->ptlViewportOrg;
-    ptWindowExt   = Dc_Attr->szlWindowExt;
-    ptWindowOrg   = Dc_Attr->ptlWindowOrg;
+  /* In GM_COMPATIBLE, don't include bottom and right edges */
+  if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+  {
+    corners[1].x--;
+    corners[1].y--;
+  }
 
-    /* Save world transform
-     * NB: The Windows documentation on world transforms would lead one to
-     * believe that this has to be done only in GM_ADVANCED; however, my
-     * tests show that resetting the graphics mode to GM_COMPATIBLE does
-     * not reset the world transform.
-     */
-    xform = dc->DcLevel.xformWorld2Wnd;
+  /* arcto: Add a PT_MOVETO only if this is the first entry in a stroke */
+  if(lines==GdiTypeArcTo && pPath->newStroke) // -1
+  {
+     pPath->newStroke=FALSE;
+     IntGetCurrentPositionEx ( dc, &pointCurPos );
+     CoordLPtoDP(dc, &pointCurPos);
+     if(!PATH_AddEntry(pPath, &pointCurPos, PT_MOVETO))
+     {
+       Ret = FALSE;
+       goto ArcExit;
+     }
+  }
 
-    /* Set MM_TEXT */
-    IntGdiSetMapMode( dc, MM_TEXT );
-    Dc_Attr->ptlViewportOrg.x = 0;
-    Dc_Attr->ptlViewportOrg.y = 0;
-    Dc_Attr->ptlWindowOrg.x = 0;
-    Dc_Attr->ptlWindowOrg.y = 0;
+  /* Add the arc to the path with one Bezier spline per quadrant that the
+   * arc spans */
+  start=TRUE;
+  end=FALSE;
+  do
+  {
+    /* Determine the start and end angles for this quadrant */
+    if(start)
+    {
+      angleStartQuadrant=angleStart;
+      if ( clockwise )
+        angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
+      else
+        angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
+    }
+    else
+    {
+      angleStartQuadrant=angleEndQuadrant;
+      if ( clockwise )
+        angleEndQuadrant+=M_PI_2;
+      else
+        angleEndQuadrant-=M_PI_2;
+    }
 
-    graphicsMode = Dc_Attr->iGraphicsMode;
-    Dc_Attr->iGraphicsMode = GM_ADVANCED;
-    IntGdiModifyWorldTransform( dc, &xform, MWT_IDENTITY );
-    Dc_Attr->iGraphicsMode =  graphicsMode;
+    /* Have we reached the last part of the arc? */
+    if ( (clockwise && angleEnd<angleEndQuadrant)
+      || (!clockwise && angleEnd>angleEndQuadrant)
+      )
+    {
+      /* Adjust the end angle for this quadrant */
+     angleEndQuadrant = angleEnd;
+     end = TRUE;
+    }
 
-    /* Paint the region */
-    IntGdiPaintRgn( dc, hrgn );
-    NtGdiDeleteObject( hrgn );
-    /* Restore the old mapping mode */
-    IntGdiSetMapMode( dc, mapMode );
-    Dc_Attr->szlViewportExt = ptViewportExt;
-    Dc_Attr->ptlViewportOrg = ptViewportOrg;
-    Dc_Attr->szlWindowExt   = ptWindowExt;
-    Dc_Attr->ptlWindowOrg   = ptWindowOrg;
+    /* Add the Bezier spline to the path */
+    PATH_DoArcPart ( pPath, corners, angleStartQuadrant, angleEndQuadrant,
+       start ? (lines==GdiTypeArcTo ? PT_LINETO : PT_MOVETO) : FALSE ); // -1
+    start = FALSE;
+  } while(!end);
 
-    /* Go to GM_ADVANCED temporarily to restore the world transform */
-    graphicsMode = Dc_Attr->iGraphicsMode;
-    Dc_Attr->iGraphicsMode = GM_ADVANCED;
-    IntGdiModifyWorldTransform( dc, &xform, MWT_MAX+1 );
-    Dc_Attr->iGraphicsMode = graphicsMode;
-    return TRUE;
+  /* chord: close figure. pie: add line and close figure */
+  if (lines==GdiTypeChord) // 1
+  {
+      IntGdiCloseFigure(pPath);
   }
-  return FALSE;
+  else if (lines==GdiTypePie) // 2
+  {
+      centre.x = (corners[0].x+corners[1].x)/2;
+      centre.y = (corners[0].y+corners[1].y)/2;
+      if(!PATH_AddEntry(pPath, &centre, PT_LINETO | PT_CLOSEFIGURE))
+         Ret = FALSE;
+  }
+ArcExit:
+  PATH_UnlockPath( pPath );
+  return Ret;
 }
 
-/* PATH_InitGdiPath
- *
- * Initializes the GdiPath structure.
- */
-VOID
+BOOL
 FASTCALL
-PATH_InitGdiPath ( GdiPath *pPath )
+PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
 {
-  ASSERT(pPath!=NULL);
+  POINT pt;
+  ULONG i;
+  PPATH pPath;
 
-  pPath->state=PATH_Null;
-  pPath->pPoints=NULL;
-  pPath->pFlags=NULL;
-  pPath->numEntriesUsed=0;
-  pPath->numEntriesAllocated=0;
-}
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( cbPoints );
 
-/* PATH_DestroyGdiPath
- *
- * Destroys a GdiPath structure (frees the memory in the arrays).
- */
-VOID
-FASTCALL
-PATH_DestroyGdiPath ( GdiPath *pPath )
-{
-  ASSERT(pPath!=NULL);
+   pPath = PATH_LockPath( dc->DcLevel.hPath );
+   if (!pPath) return FALSE;
+   
 /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
-  if (pPath->pPoints) ExFreePool(pPath->pPoints);
-  if (pPath->pFlags) ExFreePool(pPath->pFlags);
+  /* Add a PT_MOVETO if necessary */
+  if ( pPath->newStroke )
+  {
+    pPath->newStroke=FALSE;
+    IntGetCurrentPositionEx ( dc, &pt );
+    CoordLPtoDP ( dc, &pt );
+    if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+    {
+        PATH_UnlockPath( pPath );
+        return FALSE;
+    }
+  }
+
+  for(i = 0; i < cbPoints; i++)
+  {
+    pt = pts[i];
+    CoordLPtoDP ( dc, &pt );
+    PATH_AddEntry(pPath, &pt, PT_BEZIERTO);
+  }
+  PATH_UnlockPath( pPath );
+  return TRUE;
 }
 
-/* PATH_AssignGdiPath
- *
- * Copies the GdiPath structure "pPathSrc" to "pPathDest". A deep copy is
- * performed, i.e. the contents of the pPoints and pFlags arrays are copied,
- * not just the pointers. Since this means that the arrays in pPathDest may
- * need to be resized, pPathDest should have been initialized using
- * PATH_InitGdiPath (in C++, this function would be an assignment operator,
- * not a copy constructor).
- * Returns TRUE if successful, else FALSE.
- */
 BOOL
 FASTCALL
-PATH_AssignGdiPath ( GdiPath *pPathDest, const GdiPath *pPathSrc )
+PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
 {
-  ASSERT(pPathDest!=NULL && pPathSrc!=NULL);
+  POINT   pt;
+  ULONG   i;
+  PPATH   pPath;
 
-  /* Make sure destination arrays are big enough */
-  if ( !PATH_ReserveEntries(pPathDest, pPathSrc->numEntriesUsed) )
-    return FALSE;
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( cbPoints );
 
-  /* Perform the copy operation */
-  memcpy(pPathDest->pPoints, pPathSrc->pPoints,
-    sizeof(POINT)*pPathSrc->numEntriesUsed);
-  memcpy(pPathDest->pFlags, pPathSrc->pFlags,
-    sizeof(BYTE)*pPathSrc->numEntriesUsed);
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-  pPathDest->state=pPathSrc->state;
-  pPathDest->numEntriesUsed=pPathSrc->numEntriesUsed;
-  pPathDest->newStroke=pPathSrc->newStroke;
+   /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
+  for ( i = 0; i < cbPoints; i++ )
+  {
+    pt = pts[i];
+    CoordLPtoDP ( dc, &pt );
+    PATH_AddEntry ( pPath, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
+  }
+  PATH_UnlockPath( pPath );
   return TRUE;
 }
 
-/* PATH_MoveTo
- *
- * Should be called when a MoveTo is performed on a DC that has an
- * open path. This starts a new stroke. Returns TRUE if successful, else
- * FALSE.
- */
 BOOL
 FASTCALL
-PATH_MoveTo ( PDC dc )
+PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
 {
+  POINT   pt;
+  ULONG   i;
+  PPATH   pPath;
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    /* FIXME: Do we have to call SetLastError? */
-    return FALSE;
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( cbPoints );
 
-  /* Start a new stroke */
-  dc->w.path.newStroke = TRUE;
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
+  for ( i = 0; i < cbPoints; i++ )
+  {
+    pt = pts[i];
+    CoordLPtoDP ( dc, &pt );
+    PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
+  }
+  PATH_UnlockPath( pPath );
   return TRUE;
 }
 
-/* PATH_LineTo
- *
- * Should be called when a LineTo is performed on a DC that has an
- * open path. This adds a PT_LINETO entry to the path (and possibly
- * a PT_MOVETO entry, if this is the first LineTo in a stroke).
- * Returns TRUE if successful, else FALSE.
- */
 BOOL
 FASTCALL
-PATH_LineTo ( PDC dc, INT x, INT y )
+PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
 {
-  POINT point, pointCurPos;
+  POINT   pt;
+  ULONG   i;
+  PPATH   pPath;
+
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( cbPoints );
 
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
+   
   /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
     return FALSE;
-
-  /* Convert point to device coordinates */
-  point.x=x;
-  point.y=y;
-  CoordLPtoDP ( dc, &point );
+  }
 
   /* Add a PT_MOVETO if necessary */
-  if ( dc->w.path.newStroke )
+  if ( pPath->newStroke )
   {
-    dc->w.path.newStroke = FALSE;
-    IntGetCurrentPositionEx ( dc, &pointCurPos );
-    CoordLPtoDP ( dc, &pointCurPos );
-    if ( !PATH_AddEntry(&dc->w.path, &pointCurPos, PT_MOVETO) )
+    pPath->newStroke = FALSE;
+    IntGetCurrentPositionEx ( dc, &pt );
+    CoordLPtoDP ( dc, &pt );
+    if ( !PATH_AddEntry(pPath, &pt, PT_MOVETO) )
+    {
+      PATH_UnlockPath( pPath );
       return FALSE;
+    }
   }
 
-  /* Add a PT_LINETO entry */
-  return PATH_AddEntry(&dc->w.path, &point, PT_LINETO);
+  for(i = 0; i < cbPoints; i++)
+  {
+    pt = pts[i];
+    CoordLPtoDP ( dc, &pt );
+    PATH_AddEntry(pPath, &pt, PT_LINETO);
+  }
+  PATH_UnlockPath( pPath );
+  return TRUE;
 }
 
-/* PATH_Rectangle
- *
- * Should be called when a call to Rectangle is performed on a DC that has
- * an open path. Returns TRUE if successful, else FALSE.
- */
+
 BOOL
 FASTCALL
-PATH_Rectangle ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
+PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
 {
-  POINT corners[2], pointTemp;
-  INT   temp;
+  POINT   pt;
+  ULONG   i;
+  PPATH   pPath;
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+  ASSERT ( dc );
+  ASSERT ( pts );
 
-  /* Convert points to device coordinates */
-  corners[0].x=x1;
-  corners[0].y=y1;
-  corners[1].x=x2;
-  corners[1].y=y2;
-  IntLPtoDP ( dc, corners, 2 );
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-  /* Make sure first corner is top left and second corner is bottom right */
-  if ( corners[0].x > corners[1].x )
-  {
-    temp=corners[0].x;
-    corners[0].x=corners[1].x;
-    corners[1].x=temp;
-  }
-  if ( corners[0].y > corners[1].y )
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
   {
-    temp=corners[0].y;
-    corners[0].y=corners[1].y;
-    corners[1].y=temp;
+    PATH_UnlockPath( pPath );
+    return FALSE;
   }
 
-  /* In GM_COMPATIBLE, don't include bottom and right edges */
-  if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+  for(i = 0; i < cbPoints; i++)
   {
-    corners[1].x--;
-    corners[1].y--;
+    pt = pts[i];
+    CoordLPtoDP ( dc, &pt );
+    PATH_AddEntry(pPath, &pt, (i == 0) ? PT_MOVETO :
+      ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
+      PT_LINETO));
   }
+  PATH_UnlockPath( pPath );
+  return TRUE;
+}
 
-  /* Close any previous figure */
-  IntGdiCloseFigure(dc);
+BOOL
+FASTCALL
+PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
+{
+  POINT   pt, startpt;
+  ULONG   poly, point, i;
+  PPATH   pPath;
 
-  /* Add four points to the path */
-  pointTemp.x=corners[1].x;
-  pointTemp.y=corners[0].y;
-  if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_MOVETO) )
-    return FALSE;
-  if ( !PATH_AddEntry(&dc->w.path, corners, PT_LINETO) )
-    return FALSE;
-  pointTemp.x=corners[0].x;
-  pointTemp.y=corners[1].y;
-  if ( !PATH_AddEntry(&dc->w.path, &pointTemp, PT_LINETO) )
-    return FALSE;
-  if ( !PATH_AddEntry(&dc->w.path, corners+1, PT_LINETO) )
-    return FALSE;
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( counts );
+  ASSERT ( polygons );
 
-  /* Close the rectangle figure */
-  IntGdiCloseFigure(dc) ;
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
+
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
+  for(i = 0, poly = 0; poly < polygons; poly++)
+  {
+    for(point = 0; point < (ULONG) counts[poly]; point++, i++)
+    {
+      pt = pts[i];
+      CoordLPtoDP ( dc, &pt );
+      if(point == 0) startpt = pt;
+        PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+    }
+    /* win98 adds an extra line to close the figure for some reason */
+    PATH_AddEntry(pPath, &startpt, PT_LINETO | PT_CLOSEFIGURE);
+  }
+  PATH_UnlockPath( pPath );
   return TRUE;
 }
 
-/* PATH_RoundRect
- *
- * Should be called when a call to RoundRect is performed on a DC that has
- * an open path. Returns TRUE if successful, else FALSE.
- *
- * FIXME: it adds the same entries to the path as windows does, but there
- * is an error in the bezier drawing code so that there are small pixel-size
- * gaps when the resulting path is drawn by StrokePath()
- */
-BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height)
+BOOL
+FASTCALL
+PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines )
 {
-   GdiPath *pPath = &dc->w.path;
-   POINT corners[2], pointTemp;
-   FLOAT_POINT ellCorners[2];
-
-   /* Check that path is open */
-   if(pPath->state!=PATH_Open)
-      return FALSE;
+  POINT   pt;
+  ULONG   poly, point, i;
+  PPATH   pPath;
 
-   if(!PATH_CheckCorners(dc,corners,x1,y1,x2,y2))
-      return FALSE;
+  ASSERT ( dc );
+  ASSERT ( pts );
+  ASSERT ( counts );
+  ASSERT ( polylines );
 
-   /* Add points to the roundrect path */
-   ellCorners[0].x = corners[1].x-ell_width;
-   ellCorners[0].y = corners[0].y;
-   ellCorners[1].x = corners[1].x;
-   ellCorners[1].y = corners[0].y+ell_height;
-   if(!PATH_DoArcPart(pPath, ellCorners, 0, -M_PI_2, TRUE))
-      return FALSE;
-   pointTemp.x = corners[0].x+ell_width/2;
-   pointTemp.y = corners[0].y;
-   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
-      return FALSE;
-   ellCorners[0].x = corners[0].x;
-   ellCorners[1].x = corners[0].x+ell_width;
-   if(!PATH_DoArcPart(pPath, ellCorners, -M_PI_2, -M_PI, FALSE))
-      return FALSE;
-   pointTemp.x = corners[0].x;
-   pointTemp.y = corners[1].y-ell_height/2;
-   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
-      return FALSE;
-   ellCorners[0].y = corners[1].y-ell_height;
-   ellCorners[1].y = corners[1].y;
-   if(!PATH_DoArcPart(pPath, ellCorners, M_PI, M_PI_2, FALSE))
-      return FALSE;
-   pointTemp.x = corners[1].x-ell_width/2;
-   pointTemp.y = corners[1].y;
-   if(!PATH_AddEntry(pPath, &pointTemp, PT_LINETO))
-      return FALSE;
-   ellCorners[0].x = corners[1].x-ell_width;
-   ellCorners[1].x = corners[1].x;
-   if(!PATH_DoArcPart(pPath, ellCorners, M_PI_2, 0, FALSE))
-      return FALSE;
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath) return FALSE;
 
-   IntGdiCloseFigure(dc);
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
+  {
+    PATH_UnlockPath( pPath );
+    return FALSE;
+  }
 
-   return TRUE;
+  for(i = 0, poly = 0; poly < polylines; poly++)
+  {
+    for(point = 0; point < counts[poly]; point++, i++)
+    {
+      pt = pts[i];
+      CoordLPtoDP ( dc, &pt );
+      PATH_AddEntry(pPath, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+    }
+  }
+  PATH_UnlockPath( pPath );
+  return TRUE;
 }
 
-/* PATH_Ellipse
+
+/* PATH_CheckCorners
  *
- * Should be called when a call to Ellipse is performed on a DC that has
- * an open path. This adds four Bezier splines representing the ellipse
- * to the path. Returns TRUE if successful, else FALSE.
+ * Helper function for PATH_RoundRect() and PATH_Rectangle()
  */
-BOOL
-FASTCALL
-PATH_Ellipse ( PDC dc, INT x1, INT y1, INT x2, INT y2 )
+BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
 {
-  /* TODO: This should probably be revised to call PATH_AngleArc */
-  /* (once it exists) */
-  BOOL Ret = PATH_Arc ( dc, x1, y1, x2, y2, x1, (y1+y2)/2, x1, (y1+y2)/2, GdiTypeArc );
-  if (Ret) IntGdiCloseFigure(dc);
-  return Ret;
+   INT temp;
+   PDC_ATTR Dc_Attr = dc->pDc_Attr;
+   if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+   /* Convert points to device coordinates */
+   corners[0].x=x1;
+   corners[0].y=y1;
+   corners[1].x=x2;
+   corners[1].y=y2;
+   CoordLPtoDP(dc, &corners[0]);
+   CoordLPtoDP(dc, &corners[1]);
+
+   /* Make sure first corner is top left and second corner is bottom right */
+   if(corners[0].x>corners[1].x)
+   {
+      temp=corners[0].x;
+      corners[0].x=corners[1].x;
+      corners[1].x=temp;
+   }
+   if(corners[0].y>corners[1].y)
+   {
+      temp=corners[0].y;
+      corners[0].y=corners[1].y;
+      corners[1].y=temp;
+   }
+
+   /* In GM_COMPATIBLE, don't include bottom and right edges */
+   if(Dc_Attr->iGraphicsMode==GM_COMPATIBLE)
+   {
+      corners[1].x--;
+      corners[1].y--;
+   }
+
+   return TRUE;
 }
 
-/* PATH_Arc
+
+/* PATH_AddFlatBezier
  *
- * Should be called when a call to Arc is performed on a DC that has
- * an open path. This adds up to five Bezier splines representing the arc
- * to the path. When 'lines' is 1, we add 1 extra line to get a chord,
- * and when 'lines' is 2, we add 2 extra lines to get a pie.
- * Returns TRUE if successful, else FALSE.
  */
 BOOL
 FASTCALL
-PATH_Arc ( PDC dc, INT x1, INT y1, INT x2, INT y2,
-   INT xStart, INT yStart, INT xEnd, INT yEnd, INT lines)
+PATH_AddFlatBezier ( PPATH pPath, POINT *pt, BOOL closed )
 {
-  double  angleStart, angleEnd, angleStartQuadrant, angleEndQuadrant=0.0;
-          /* Initialize angleEndQuadrant to silence gcc's warning */
-  double  x, y;
-  FLOAT_POINT corners[2], pointStart, pointEnd;
-  POINT   centre;
-  BOOL    start, end;
-  INT     temp;
-  BOOL    clockwise;
+  POINT *pts;
+  INT no, i;
 
-  /* FIXME: This function should check for all possible error returns */
-  /* FIXME: Do we have to respect newStroke? */
+  pts = GDI_Bezier( pt, 4, &no );
+  if ( !pts ) return FALSE;
 
-  ASSERT ( dc );
+  for(i = 1; i < no; i++)
+    PATH_AddEntry(pPath, &pts[i],  (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO);
 
-  clockwise = ((dc->DcLevel.flPath & DCPATH_CLOCKWISE) != 0);
+  ExFreePool(pts);
+  return TRUE;
+}
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+/* PATH_FlattenPath
+ *
+ * Replaces Beziers with line segments
+ *
+ */
+BOOL
+FASTCALL
+PATH_FlattenPath(PPATH pPath)
+{
+  PATH newPath;
+  INT srcpt;
 
-  /* FIXME: Do we have to close the current figure? */
+  RtlZeroMemory(&newPath, sizeof(newPath));
+  newPath.state = PATH_Open;
+  for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
+    switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
+      case PT_MOVETO:
+      case PT_LINETO:
+        PATH_AddEntry(&newPath, &pPath->pPoints[srcpt], pPath->pFlags[srcpt]);
+        break;
+      case PT_BEZIERTO:
+        PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1], pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE);
+        srcpt += 2;
+        break;
+    }
+  }
+  newPath.state = PATH_Closed;
+  PATH_AssignGdiPath(pPath, &newPath);
+  PATH_EmptyPath(&newPath);
+  return TRUE;
+}
 
-  /* Check for zero height / width */
-  /* FIXME: Only in GM_COMPATIBLE? */
-  if ( x1==x2 || y1==y2 )
-    return TRUE;
 
-  /* Convert points to device coordinates */
-  corners[0].x=(FLOAT)x1;
-  corners[0].y=(FLOAT)y1;
-  corners[1].x=(FLOAT)x2;
-  corners[1].y=(FLOAT)y2;
-  pointStart.x=(FLOAT)xStart;
-  pointStart.y=(FLOAT)yStart;
-  pointEnd.x=(FLOAT)xEnd;
-  pointEnd.y=(FLOAT)yEnd;
-  INTERNAL_LPTODP_FLOAT(dc, corners);
-  INTERNAL_LPTODP_FLOAT(dc, corners+1);
-  INTERNAL_LPTODP_FLOAT(dc, &pointStart);
-  INTERNAL_LPTODP_FLOAT(dc, &pointEnd);
+HRGN FASTCALL IntCreatePolyPolygonRgn(POINT *Pts, INT *Count, INT nbpolygons,INT mode);
+/* PATH_PathToRegion
+ *
+ * Creates a region from the specified path using the specified polygon
+ * filling mode. The path is left unchanged. A handle to the region that
+ * was created is stored in *pHrgn. If successful, TRUE is returned; if an
+ * error occurs, SetLastError is called with the appropriate value and
+ * FALSE is returned.
+ */
+BOOL
+FASTCALL
+PATH_PathToRegion ( PPATH pPath, INT nPolyFillMode, HRGN *pHrgn )
+{
+  int    numStrokes, iStroke, i;
+  INT  *pNumPointsInStroke;
+  HRGN hrgn = 0;
 
-  /* Make sure first corner is top left and second corner is bottom right */
-  if ( corners[0].x > corners[1].x )
-  {
-    temp=corners[0].x;
-    corners[0].x=corners[1].x;
-    corners[1].x=temp;
-  }
-  if ( corners[0].y > corners[1].y )
-  {
-    temp=corners[0].y;
-    corners[0].y=corners[1].y;
-    corners[1].y=temp;
-  }
+  ASSERT(pPath!=NULL);
+  ASSERT(pHrgn!=NULL);
 
-  /* Compute start and end angle */
-  PATH_NormalizePoint(corners, &pointStart, &x, &y);
-  angleStart=atan2(y, x);
-  PATH_NormalizePoint(corners, &pointEnd, &x, &y);
-  angleEnd=atan2(y, x);
+  PATH_FlattenPath ( pPath );
 
-  /* Make sure the end angle is "on the right side" of the start angle */
-  if ( clockwise )
-  {
-    if ( angleEnd <= angleStart )
-    {
-      angleEnd+=2*M_PI;
-      ASSERT(angleEnd>=angleStart);
-    }
-  }
-  else
-  {
-    if(angleEnd>=angleStart)
-    {
-      angleEnd-=2*M_PI;
-      ASSERT(angleEnd<=angleStart);
-    }
-  }
+  /* FIXME: What happens when number of points is zero? */
 
-  /* In GM_COMPATIBLE, don't include bottom and right edges */
-  if ( IntGetGraphicsMode(dc) == GM_COMPATIBLE )
+  /* First pass: Find out how many strokes there are in the path */
+  /* FIXME: We could eliminate this with some bookkeeping in GdiPath */
+  numStrokes=0;
+  for(i=0; i<pPath->numEntriesUsed; i++)
+    if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
+      numStrokes++;
+
+  /* Allocate memory for number-of-points-in-stroke array */
+  pNumPointsInStroke=(int *)ExAllocatePoolWithTag(PagedPool, sizeof(int) * numStrokes, TAG_PATH);
+  if(!pNumPointsInStroke)
   {
-    corners[1].x--;
-    corners[1].y--;
+    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+    return FALSE;
   }
 
-  /* Add the arc to the path with one Bezier spline per quadrant that the
-   * arc spans */
-  start=TRUE;
-  end=FALSE;
-  do
+  /* Second pass: remember number of points in each polygon */
+  iStroke=-1;  /* Will get incremented to 0 at beginning of first stroke */
+  for(i=0; i<pPath->numEntriesUsed; i++)
   {
-    /* Determine the start and end angles for this quadrant */
-    if(start)
-    {
-      angleStartQuadrant=angleStart;
-      if ( clockwise )
-        angleEndQuadrant=(floor(angleStart/M_PI_2)+1.0)*M_PI_2;
-      else
-        angleEndQuadrant=(ceil(angleStart/M_PI_2)-1.0)*M_PI_2;
-    }
-    else
+    /* Is this the beginning of a new stroke? */
+    if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
     {
-      angleStartQuadrant=angleEndQuadrant;
-      if ( clockwise )
-        angleEndQuadrant+=M_PI_2;
-      else
-        angleEndQuadrant-=M_PI_2;
+      iStroke++;
+      pNumPointsInStroke[iStroke]=0;
     }
 
-    /* Have we reached the last part of the arc? */
-    if ( (clockwise && angleEnd<angleEndQuadrant)
-      || (!clockwise && angleEnd>angleEndQuadrant)
-      )
-    {
-      /* Adjust the end angle for this quadrant */
-     angleEndQuadrant = angleEnd;
-     end = TRUE;
-    }
+    pNumPointsInStroke[iStroke]++;
+  }
 
-    /* Add the Bezier spline to the path */
-    PATH_DoArcPart ( &dc->w.path, corners, angleStartQuadrant, angleEndQuadrant, start );
-    start = FALSE;
-  } while(!end);
+  /* Create a region from the strokes */
+  hrgn = IntCreatePolyPolygonRgn( pPath->pPoints,
+                              pNumPointsInStroke,
+                                      numStrokes,
+                                   nPolyFillMode);
+  if(hrgn==(HRGN)0)
+  {
+    SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+    return FALSE;
+  }
 
-  /* chord: close figure. pie: add line and close figure */
-  if(lines==GdiTypeChord) // 1
-   {
-      IntGdiCloseFigure(dc);
-   }
-  else if(lines==GdiTypePie) // 2
-   {
-      centre.x = (corners[0].x+corners[1].x)/2;
-      centre.y = (corners[0].y+corners[1].y)/2;
-      if(!PATH_AddEntry(&dc->w.path, &centre, PT_LINETO | PT_CLOSEFIGURE))
-         return FALSE;
-   }
+  /* Free memory for number-of-points-in-stroke array */
+  ExFreePool(pNumPointsInStroke);
 
+  /* Success! */
+  *pHrgn=hrgn;
   return TRUE;
 }
 
-BOOL
+/* PATH_EmptyPath
+ *
+ * Removes all entries from the path and sets the path state to PATH_Null.
+ */
+VOID
 FASTCALL
-PATH_PolyBezierTo ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_EmptyPath ( PPATH pPath )
 {
-  POINT pt;
-  ULONG i;
-
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( cbPoints );
+  ASSERT(pPath!=NULL);
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
-
-  /* Add a PT_MOVETO if necessary */
-  if ( dc->w.path.newStroke )
-  {
-    dc->w.path.newStroke=FALSE;
-    IntGetCurrentPositionEx ( dc, &pt );
-    CoordLPtoDP ( dc, &pt );
-    if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
-        return FALSE;
-  }
-
-  for(i = 0; i < cbPoints; i++)
-  {
-    pt = pts[i];
-    CoordLPtoDP ( dc, &pt );
-    PATH_AddEntry(&dc->w.path, &pt, PT_BEZIERTO);
-  }
-  return TRUE;
+  pPath->state=PATH_Null;
+  pPath->numEntriesUsed=0;
 }
 
+/* PATH_AddEntry
+ *
+ * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
+ * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
+ * successful, FALSE otherwise (e.g. if not enough memory was available).
+ */
 BOOL
 FASTCALL
-PATH_PolyBezier ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_AddEntry ( PPATH pPath, const POINT *pPoint, BYTE flags )
 {
-  POINT   pt;
-  ULONG   i;
+  ASSERT(pPath!=NULL);
 
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( cbPoints );
+  /* FIXME: If newStroke is true, perhaps we want to check that we're
+   * getting a PT_MOVETO
+   */
 
-   /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
+  /* Check that path is open */
+  if ( pPath->state != PATH_Open )
     return FALSE;
 
-  for ( i = 0; i < cbPoints; i++ )
-  {
-    pt = pts[i];
-    CoordLPtoDP ( dc, &pt );
-    PATH_AddEntry ( &dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_BEZIERTO );
-  }
-
-  return TRUE;
-}
+  /* Reserve enough memory for an extra path entry */
+  if ( !PATH_ReserveEntries(pPath, pPath->numEntriesUsed+1) )
+    return FALSE;
 
-BOOL
-FASTCALL
-PATH_Polyline ( PDC dc, const POINT *pts, DWORD cbPoints )
-{
-  POINT   pt;
-  ULONG   i;
+  /* Store information in path entry */
+  pPath->pPoints[pPath->numEntriesUsed]=*pPoint;
+  pPath->pFlags[pPath->numEntriesUsed]=flags;
 
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( cbPoints );
+  /* If this is PT_CLOSEFIGURE, we have to start a new stroke next time */
+  if((flags & PT_CLOSEFIGURE) == PT_CLOSEFIGURE)
+    pPath->newStroke=TRUE;
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+  /* Increment entry count */
+  pPath->numEntriesUsed++;
 
-  for ( i = 0; i < cbPoints; i++ )
-  {
-    pt = pts[i];
-    CoordLPtoDP ( dc, &pt );
-    PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO : PT_LINETO);
-  }
   return TRUE;
 }
 
+/* PATH_ReserveEntries
+ *
+ * Ensures that at least "numEntries" entries (for points and flags) have
+ * been allocated; allocates larger arrays and copies the existing entries
+ * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
+ */
 BOOL
 FASTCALL
-PATH_PolylineTo ( PDC dc, const POINT *pts, DWORD cbPoints )
+PATH_ReserveEntries ( PPATH pPath, INT numEntries )
 {
-  POINT   pt;
-  ULONG   i;
-
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( cbPoints );
-
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+  INT   numEntriesToAllocate;
+  POINT *pPointsNew;
+  BYTE    *pFlagsNew;
 
-  /* Add a PT_MOVETO if necessary */
-  if ( dc->w.path.newStroke )
-  {
-    dc->w.path.newStroke = FALSE;
-    IntGetCurrentPositionEx ( dc, &pt );
-    CoordLPtoDP ( dc, &pt );
-    if ( !PATH_AddEntry(&dc->w.path, &pt, PT_MOVETO) )
-      return FALSE;
-  }
+  ASSERT(pPath!=NULL);
+  ASSERT(numEntries>=0);
 
-  for(i = 0; i < cbPoints; i++)
+  /* Do we have to allocate more memory? */
+  if(numEntries > pPath->numEntriesAllocated)
   {
-    pt = pts[i];
-    CoordLPtoDP ( dc, &pt );
-    PATH_AddEntry(&dc->w.path, &pt, PT_LINETO);
-  }
-
-  return TRUE;
-}
-
+    /* Find number of entries to allocate. We let the size of the array
+     * grow exponentially, since that will guarantee linear time
+     * complexity. */
+    if(pPath->numEntriesAllocated)
+    {
+      numEntriesToAllocate=pPath->numEntriesAllocated;
+      while(numEntriesToAllocate<numEntries)
+        numEntriesToAllocate=numEntriesToAllocate*GROW_FACTOR_NUMER/GROW_FACTOR_DENOM;
+    } else
+       numEntriesToAllocate=numEntries;
 
-BOOL
-FASTCALL
-PATH_Polygon ( PDC dc, const POINT *pts, DWORD cbPoints )
-{
-  POINT   pt;
-  ULONG   i;
+    /* Allocate new arrays */
+    pPointsNew=(POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH);
+    if(!pPointsNew)
+      return FALSE;
+    pFlagsNew=(BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH);
+    if(!pFlagsNew)
+    {
+      ExFreePool(pPointsNew);
+      return FALSE;
+    }
 
-  ASSERT ( dc );
-  ASSERT ( pts );
+    /* Copy old arrays to new arrays and discard old arrays */
+    if(pPath->pPoints)
+    {
+      ASSERT(pPath->pFlags);
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+      memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
+      memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
 
-  for(i = 0; i < cbPoints; i++)
-  {
-    pt = pts[i];
-    CoordLPtoDP ( dc, &pt );
-    PATH_AddEntry(&dc->w.path, &pt, (i == 0) ? PT_MOVETO :
-      ((i == cbPoints-1) ? PT_LINETO | PT_CLOSEFIGURE :
-      PT_LINETO));
+      ExFreePool(pPath->pPoints);
+      ExFreePool(pPath->pFlags);
+    }
+    pPath->pPoints=pPointsNew;
+    pPath->pFlags=pFlagsNew;
+    pPath->numEntriesAllocated=numEntriesToAllocate;
   }
+
   return TRUE;
 }
 
+/* PATH_DoArcPart
+ *
+ * Creates a Bezier spline that corresponds to part of an arc and appends the
+ * corresponding points to the path. The start and end angles are passed in
+ * "angleStart" and "angleEnd"; these angles should span a quarter circle
+ * at most. If "startEntryType" is non-zero, an entry of that type for the first
+ * control point is added to the path; otherwise, it is assumed that the current
+ * position is equal to the first control point.
+ */
 BOOL
 FASTCALL
-PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons )
+PATH_DoArcPart ( PPATH pPath, FLOAT_POINT corners[],
+   double angleStart, double angleEnd, BYTE startEntryType )
 {
-  POINT   pt, startpt;
-  ULONG   poly, point, i;
+  double  halfAngle, a;
+  double  xNorm[4], yNorm[4];
+  POINT point;
+  int i;
 
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( counts );
-  ASSERT ( polygons );
+  ASSERT(fabs(angleEnd-angleStart)<=M_PI_2);
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open );
-    return FALSE;
+  /* FIXME: Is there an easier way of computing this? */
 
-  for(i = 0, poly = 0; poly < polygons; poly++)
+  /* Compute control points */
+  halfAngle=(angleEnd-angleStart)/2.0;
+  if(fabs(halfAngle)>1e-8)
   {
-    for(point = 0; point < (ULONG) counts[poly]; point++, i++)
+    a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
+    xNorm[0]=cos(angleStart);
+    yNorm[0]=sin(angleStart);
+    xNorm[1]=xNorm[0] - a*yNorm[0];
+    yNorm[1]=yNorm[0] + a*xNorm[0];
+    xNorm[3]=cos(angleEnd);
+    yNorm[3]=sin(angleEnd);
+    xNorm[2]=xNorm[3] + a*yNorm[3];
+    yNorm[2]=yNorm[3] - a*xNorm[3];
+  } else
+    for(i=0; i<4; i++)
     {
-      pt = pts[i];
-      CoordLPtoDP ( dc, &pt );
-      if(point == 0) startpt = pt;
-        PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
+      xNorm[i]=cos(angleStart);
+      yNorm[i]=sin(angleStart);
     }
-    /* win98 adds an extra line to close the figure for some reason */
-    PATH_AddEntry(&dc->w.path, &startpt, PT_LINETO | PT_CLOSEFIGURE);
-  }
-  return TRUE;
-}
-
-BOOL
-FASTCALL
-PATH_PolyPolyline ( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines )
-{
-  POINT   pt;
-  ULONG   poly, point, i;
-
-  ASSERT ( dc );
-  ASSERT ( pts );
-  ASSERT ( counts );
-  ASSERT ( polylines );
 
-  /* Check that path is open */
-  if ( dc->w.path.state != PATH_Open )
-    return FALSE;
+  /* Add starting point to path if desired */
+  if(startEntryType)
+  {
+    PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
+    if(!PATH_AddEntry(pPath, &point, startEntryType))
+      return FALSE;
+  }
 
-  for(i = 0, poly = 0; poly < polylines; poly++)
+  /* Add remaining control points */
+  for(i=1; i<4; i++)
   {
-    for(point = 0; point < counts[poly]; point++, i++)
-    {
-      pt = pts[i];
-      CoordLPtoDP ( dc, &pt );
-      PATH_AddEntry(&dc->w.path, &pt, (point == 0) ? PT_MOVETO : PT_LINETO);
-    }
+    PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
+    if(!PATH_AddEntry(pPath, &point, PT_BEZIERTO))
+      return FALSE;
   }
+
   return TRUE;
 }
 
-/***********************************************************************
- * Internal functions
- */
-
-/* PATH_CheckCorners
+/* PATH_ScaleNormalizedPoint
  *
- * Helper function for PATH_RoundRect() and PATH_Rectangle()
+ * Scales a normalized point (x, y) with respect to the box whose corners are
+ * passed in "corners". The point is stored in "*pPoint". The normalized
+ * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
+ * (1.0, 1.0) correspond to corners[1].
  */
-BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2)
+VOID
+FASTCALL
+PATH_ScaleNormalizedPoint ( FLOAT_POINT corners[], double x,
+   double y, POINT *pPoint )
 {
-   INT temp;
-   PDC_ATTR Dc_Attr = dc->pDc_Attr;
-   if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-
-   /* Convert points to device coordinates */
-   corners[0].x=x1;
-   corners[0].y=y1;
-   corners[1].x=x2;
-   corners[1].y=y2;
-   CoordLPtoDP(dc, &corners[0]);
-   CoordLPtoDP(dc, &corners[1]);
-
-   /* Make sure first corner is top left and second corner is bottom right */
-   if(corners[0].x>corners[1].x)
-   {
-      temp=corners[0].x;
-      corners[0].x=corners[1].x;
-      corners[1].x=temp;
-   }
-   if(corners[0].y>corners[1].y)
-   {
-      temp=corners[0].y;
-      corners[0].y=corners[1].y;
-      corners[1].y=temp;
-   }
-
-   /* In GM_COMPATIBLE, don't include bottom and right edges */
-   if(Dc_Attr->iGraphicsMode==GM_COMPATIBLE)
-   {
-      corners[1].x--;
-      corners[1].y--;
-   }
-
-   return TRUE;
+  ASSERT ( corners );
+  ASSERT ( pPoint );
+  pPoint->x=GDI_ROUND( (double)corners[0].x + (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
+  pPoint->y=GDI_ROUND( (double)corners[0].y + (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
 }
 
-
-/* PATH_AddFlatBezier
+/* PATH_NormalizePoint
  *
+ * Normalizes a point with respect to the box whose corners are passed in
+ * corners. The normalized coordinates are stored in *pX and *pY.
  */
-BOOL
+VOID
 FASTCALL
-PATH_AddFlatBezier ( GdiPath *pPath, POINT *pt, BOOL closed )
+PATH_NormalizePoint ( FLOAT_POINT corners[],
+   const FLOAT_POINT *pPoint,
+   double *pX, double *pY)
 {
-  POINT *pts;
-  INT no, i;
+  ASSERT ( corners );
+  ASSERT ( pPoint );
+  ASSERT ( pX );
+  ASSERT ( pY );
+  *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
+  *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
+}
 
-  pts = GDI_Bezier( pt, 4, &no );
-  if ( !pts ) return FALSE;
 
-  for(i = 1; i < no; i++)
-    PATH_AddEntry(pPath, &pts[i],  (i == no-1 && closed) ? PT_LINETO | PT_CLOSEFIGURE : PT_LINETO);
+BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath)
+{
+    BOOL ret = FALSE;
+    INT i=0;
+    INT nLinePts, nAlloc;
+    POINT *pLinePts = NULL;
+    POINT ptViewportOrg, ptWindowOrg;
+    SIZE szViewportExt, szWindowExt;
+    DWORD mapMode, graphicsMode;
+    XFORM xform;
+    PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
-  ExFreePool(pts);
-  return TRUE;
-}
+    DPRINT("Enter %s\n", __FUNCTION__);
 
-/* PATH_FlattenPath
- *
- * Replaces Beziers with line segments
- *
- */
-BOOL
-FASTCALL
-PATH_FlattenPath(GdiPath *pPath)
-{
-  GdiPath newPath;
-  INT srcpt;
+    if (pPath->state != PATH_Closed)
+        return FALSE;
 
-  RtlZeroMemory(&newPath, sizeof(newPath));
-  newPath.state = PATH_Open;
-  for(srcpt = 0; srcpt < pPath->numEntriesUsed; srcpt++) {
-    switch(pPath->pFlags[srcpt] & ~PT_CLOSEFIGURE) {
-      case PT_MOVETO:
-      case PT_LINETO:
-        PATH_AddEntry(&newPath, &pPath->pPoints[srcpt], pPath->pFlags[srcpt]);
-        break;
-      case PT_BEZIERTO:
-        PATH_AddFlatBezier(&newPath, &pPath->pPoints[srcpt-1], pPath->pFlags[srcpt+2] & PT_CLOSEFIGURE);
-        srcpt += 2;
-        break;
-    }
-  }
-  newPath.state = PATH_Closed;
-  PATH_AssignGdiPath(pPath, &newPath);
-  PATH_EmptyPath(&newPath);
-  return TRUE;
-}
+    if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+    /* Save the mapping mode info */
+    mapMode = Dc_Attr->iMapMode;
+    IntGetViewportExtEx(dc, &szViewportExt);
+    IntGetViewportOrgEx(dc, &ptViewportOrg);
+    IntGetWindowExtEx(dc, &szWindowExt);
+    IntGetWindowOrgEx(dc, &ptWindowOrg);
+    xform = dc->DcLevel.xformWorld2Wnd;
 
-/* PATH_PathToRegion
- *
- * Creates a region from the specified path using the specified polygon
- * filling mode. The path is left unchanged. A handle to the region that
- * was created is stored in *pHrgn. If successful, TRUE is returned; if an
- * error occurs, SetLastError is called with the appropriate value and
- * FALSE is returned.
- */
+    /* Set MM_TEXT */
+    Dc_Attr->iMapMode = MM_TEXT;
+    Dc_Attr->ptlViewportOrg.x = 0;
+    Dc_Attr->ptlViewportOrg.y = 0;
+    Dc_Attr->ptlWindowOrg.x = 0;
+    Dc_Attr->ptlWindowOrg.y = 0;
+    graphicsMode = Dc_Attr->iGraphicsMode;
+    Dc_Attr->iGraphicsMode = GM_ADVANCED;
+    IntGdiModifyWorldTransform(dc, &xform, MWT_IDENTITY);
+    Dc_Attr->iGraphicsMode = graphicsMode;
 
+    /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
+     * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
+     * space in case we get one to keep the number of reallocations small. */
+    nAlloc = pPath->numEntriesUsed + 1 + 300;
+    pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
+    if(!pLinePts)
+    {
+        DPRINT1("Can't allocate pool!\n");
+        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+        goto end;
+    }
+    nLinePts = 0;
 
-BOOL
-FASTCALL
-PATH_PathToRegion ( GdiPath *pPath, INT nPolyFillMode, HRGN *pHrgn )
-{
-  int    numStrokes, iStroke, i;
-  INT  *pNumPointsInStroke;
-  HRGN hrgn = 0;
+    for(i = 0; i < pPath->numEntriesUsed; i++)
+    {
+        if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE))
+                && (pPath->pFlags[i] != PT_MOVETO))
+        {
+            DPRINT1("Expected PT_MOVETO %s, got path flag %d\n",
+                i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+                (INT)pPath->pFlags[i]);
+                goto end;
+        }
 
-  ASSERT(pPath!=NULL);
-  ASSERT(pHrgn!=NULL);
+        switch(pPath->pFlags[i])
+        {
+        case PT_MOVETO:
+            DPRINT("Got PT_MOVETO (%ld, %ld)\n",
+                pPath->pPoints[i].x, pPath->pPoints[i].y);
+            if(nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
+            nLinePts = 0;
+            pLinePts[nLinePts++] = pPath->pPoints[i];
+            break;
+        case PT_LINETO:
+        case (PT_LINETO | PT_CLOSEFIGURE):
+            DPRINT("Got PT_LINETO (%ld, %ld)\n",
+              pPath->pPoints[i].x, pPath->pPoints[i].y);
+            pLinePts[nLinePts++] = pPath->pPoints[i];
+            break;
+        case PT_BEZIERTO:
+            DPRINT("Got PT_BEZIERTO\n");
+            if(pPath->pFlags[i+1] != PT_BEZIERTO ||
+               (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
+            {
+                DPRINT1("Path didn't contain 3 successive PT_BEZIERTOs\n");
+                ret = FALSE;
+                goto end;
+            }
+            else
+            {
+                INT nBzrPts, nMinAlloc;
+                POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
+                /* Make sure we have allocated enough memory for the lines of
+                 * this bezier and the rest of the path, assuming we won't get
+                 * another one (since we won't reallocate again then). */
+                nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
+                if(nAlloc < nMinAlloc)
+                {
+                    // Reallocate memory
 
-  PATH_FlattenPath ( pPath );
+                    POINT *Realloc = NULL;
+                    nAlloc = nMinAlloc * 2;
 
-  /* FIXME: What happens when number of points is zero? */
+                    Realloc = ExAllocatePoolWithTag(PagedPool,
+                        nAlloc * sizeof(POINT),
+                        TAG_PATH);
 
-  /* First pass: Find out how many strokes there are in the path */
-  /* FIXME: We could eliminate this with some bookkeeping in GdiPath */
-  numStrokes=0;
-  for(i=0; i<pPath->numEntriesUsed; i++)
-    if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
-      numStrokes++;
+                    if(!Realloc)
+                    {
+                        DPRINT1("Can't allocate pool!\n");
+                        goto end;
+                    }
 
-  /* Allocate memory for number-of-points-in-stroke array */
-  pNumPointsInStroke=(int *)ExAllocatePoolWithTag(PagedPool, sizeof(int) * numStrokes, TAG_PATH);
-  if(!pNumPointsInStroke)
-  {
-//    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    return FALSE;
-  }
+                    memcpy(Realloc, pLinePts, nLinePts*sizeof(POINT));
+                    ExFreePool(pLinePts);
+                    pLinePts = Realloc;
+                }
+                memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
+                nLinePts += nBzrPts - 1;
+                ExFreePool(pBzrPts);
+                i += 2;
+            }
+            break;
+        default:
+            DPRINT1("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
+            goto end;
+        }
 
-  /* Second pass: remember number of points in each polygon */
-  iStroke=-1;  /* Will get incremented to 0 at beginning of first stroke */
-  for(i=0; i<pPath->numEntriesUsed; i++)
-  {
-    /* Is this the beginning of a new stroke? */
-    if((pPath->pFlags[i] & ~PT_CLOSEFIGURE) == PT_MOVETO)
-    {
-      iStroke++;
-      pNumPointsInStroke[iStroke]=0;
+        if(pPath->pFlags[i] & PT_CLOSEFIGURE)
+        {
+            pLinePts[nLinePts++] = pLinePts[0];
+        }
     }
+    if(nLinePts >= 2)
+        IntGdiPolyline(dc, pLinePts, nLinePts);
 
-    pNumPointsInStroke[iStroke]++;
-  }
-
-  /* Create a region from the strokes */
-/*  hrgn=CreatePolyPolygonRgn(pPath->pPoints, pNumPointsInStroke,
-    numStrokes, nPolyFillMode); FIXME: reinclude when region code implemented */
-  if(hrgn==(HRGN)0)
-  {
-//    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-    return FALSE;
-  }
+    ret = TRUE;
 
-  /* Free memory for number-of-points-in-stroke array */
-  ExFreePool(pNumPointsInStroke);
+end:
+    if(pLinePts)ExFreePool(pLinePts);
 
-  /* Success! */
-  *pHrgn=hrgn;
-  return TRUE;
-}
+    /* Restore the old mapping mode */
+    Dc_Attr->iMapMode =  mapMode;
+    Dc_Attr->szlWindowExt.cx = szWindowExt.cx;
+    Dc_Attr->szlWindowExt.cy = szWindowExt.cy;
+    Dc_Attr->ptlWindowOrg.x = ptWindowOrg.x;
+    Dc_Attr->ptlWindowOrg.y = ptWindowOrg.y;
 
-/* PATH_EmptyPath
- *
- * Removes all entries from the path and sets the path state to PATH_Null.
- */
-VOID
-FASTCALL
-PATH_EmptyPath ( GdiPath *pPath )
-{
-  ASSERT(pPath!=NULL);
+    Dc_Attr->szlViewportExt.cx = szViewportExt.cx;
+    Dc_Attr->szlViewportExt.cy = szViewportExt.cy;
+    Dc_Attr->ptlViewportOrg.x = ptViewportOrg.x;
+    Dc_Attr->ptlViewportOrg.y = ptViewportOrg.y;
 
-  pPath->state=PATH_Null;
-  pPath->numEntriesUsed=0;
+    /* Restore the world transform */
+    dc->DcLevel.xformWorld2Wnd = xform;
+
+    /* If we've moved the current point then get its new position
+       which will be in device (MM_TEXT) co-ords, convert it to
+       logical co-ords and re-set it.  This basically updates
+       dc->CurPosX|Y so that their values are in the correct mapping
+       mode.
+    */
+    if(i > 0)
+    {
+        POINT pt;
+        IntGetCurrentPositionEx(dc, &pt);
+        IntDPtoLP(dc, &pt, 1);
+        IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
+    }
+    DPRINT("Leave %s, ret=%d\n", __FUNCTION__, ret);
+    return ret;
 }
 
-/* PATH_AddEntry
- *
- * Adds an entry to the path. For "flags", pass either PT_MOVETO, PT_LINETO
- * or PT_BEZIERTO, optionally ORed with PT_CLOSEFIGURE. Returns TRUE if
- * successful, FALSE otherwise (e.g. if not enough memory was available).
- */
+#define round(x) ((int)((x)>0?(x)+0.5:(x)-0.5))
+
+static
 BOOL
 FASTCALL
-PATH_AddEntry ( GdiPath *pPath, const POINT *pPoint, BYTE flags )
+PATH_WidenPath(DC *dc)
 {
-  ASSERT(pPath!=NULL);
+    INT i, j, numStrokes, penWidth, penWidthIn, penWidthOut, size, penStyle;
+    BOOL ret = FALSE;
+    PPATH pPath, pNewPath, *pStrokes, pUpPath, pDownPath;
+    EXTLOGPEN *elp;
+    DWORD obj_type, joint, endcap, penType;
+    PDC_ATTR Dc_Attr = dc->pDc_Attr;
 
-  /* FIXME: If newStroke is true, perhaps we want to check that we're
-   * getting a PT_MOVETO
-   */
+    pPath = PATH_LockPath( dc->DcLevel.hPath );
+    if (!pPath) return FALSE;
 
-  /* Check that path is open */
-  if ( pPath->state != PATH_Open )
-    return FALSE;
+    if(pPath->state == PATH_Open)
+    {
+       PATH_UnlockPath( pPath );
+       SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+       return FALSE;
+    }
 
-  /* Reserve enough memory for an extra path entry */
-  if ( !PATH_ReserveEntries(pPath, pPath->numEntriesUsed+1) )
-    return FALSE;
+    if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
 
-  /* Store information in path entry */
-  pPath->pPoints[pPath->numEntriesUsed]=*pPoint;
-  pPath->pFlags[pPath->numEntriesUsed]=flags;
+    PATH_FlattenPath(pPath);
 
-  /* If this is PT_CLOSEFIGURE, we have to start a new stroke next time */
-  if((flags & PT_CLOSEFIGURE) == PT_CLOSEFIGURE)
-    pPath->newStroke=TRUE;
+    size = IntGdiGetObject( Dc_Attr->hpen, 0, NULL);
+    if (!size)
+    {
+        PATH_UnlockPath( pPath );
+        SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+        return FALSE;
+    }
 
-  /* Increment entry count */
-  pPath->numEntriesUsed++;
+    elp = ExAllocatePoolWithTag(PagedPool, size, TAG_PATH);
+    (VOID) IntGdiGetObject( Dc_Attr->hpen, size, elp);
 
-  return TRUE;
-}
+    obj_type = GDIOBJ_GetObjectType(Dc_Attr->hpen);
+    if(obj_type == GDI_OBJECT_TYPE_PEN)
+    {
+        penStyle = ((LOGPEN*)elp)->lopnStyle;
+    }
+    else if(obj_type == GDI_OBJECT_TYPE_EXTPEN)
+    {
+        penStyle = elp->elpPenStyle;
+    }
+    else
+    {
+        SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+        ExFreePool(elp);
+        PATH_UnlockPath( pPath );
+        return FALSE;
+    }
 
-/* PATH_ReserveEntries
- *
- * Ensures that at least "numEntries" entries (for points and flags) have
- * been allocated; allocates larger arrays and copies the existing entries
- * to those arrays, if necessary. Returns TRUE if successful, else FALSE.
- */
-BOOL
-FASTCALL
-PATH_ReserveEntries ( GdiPath *pPath, INT numEntries )
-{
-  INT   numEntriesToAllocate;
-  POINT *pPointsNew;
-  BYTE    *pFlagsNew;
+    penWidth = elp->elpWidth;
+    ExFreePool(elp);
 
-  ASSERT(pPath!=NULL);
-  ASSERT(numEntries>=0);
+    endcap = (PS_ENDCAP_MASK & penStyle);
+    joint = (PS_JOIN_MASK & penStyle);
+    penType = (PS_TYPE_MASK & penStyle);
 
-  /* Do we have to allocate more memory? */
-  if(numEntries > pPath->numEntriesAllocated)
-  {
-    /* Find number of entries to allocate. We let the size of the array
-     * grow exponentially, since that will guarantee linear time
-     * complexity. */
-    if(pPath->numEntriesAllocated)
+    /* The function cannot apply to cosmetic pens */
+    if(obj_type == GDI_OBJECT_TYPE_EXTPEN && penType == PS_COSMETIC)
     {
-      numEntriesToAllocate=pPath->numEntriesAllocated;
-      while(numEntriesToAllocate<numEntries)
-        numEntriesToAllocate=numEntriesToAllocate*GROW_FACTOR_NUMER/GROW_FACTOR_DENOM;
-    } else
-       numEntriesToAllocate=numEntries;
+        PATH_UnlockPath( pPath );
+        SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+        return FALSE;
+    }
 
-    /* Allocate new arrays */
-    pPointsNew=(POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH);
-    if(!pPointsNew)
-      return FALSE;
-    pFlagsNew=(BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH);
-    if(!pFlagsNew)
+    penWidthIn = penWidth / 2;
+    penWidthOut = penWidth / 2;
+    if(penWidthIn + penWidthOut < penWidth)
+        penWidthOut++;
+
+    numStrokes = 0;
+
+    pStrokes    = ExAllocatePoolWithTag(PagedPool, sizeof(PPATH), TAG_PATH);
+    pStrokes[0] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+    PATH_InitGdiPath(pStrokes[0]);
+    pStrokes[0]->pFlags =   ExAllocatePoolWithTag(PagedPool, pPath->numEntriesUsed * sizeof(INT), TAG_PATH);
+    pStrokes[0]->pPoints =  ExAllocatePoolWithTag(PagedPool, pPath->numEntriesUsed * sizeof(POINT), TAG_PATH);
+    pStrokes[0]->numEntriesUsed = 0;
+
+    for(i = 0, j = 0; i < pPath->numEntriesUsed; i++, j++)
     {
-      ExFreePool(pPointsNew);
-      return FALSE;
+        POINT point;
+        if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE)) &&
+            (pPath->pFlags[i] != PT_MOVETO))
+        {
+            DPRINT1("Expected PT_MOVETO %s, got path flag %c\n",
+                i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+                pPath->pFlags[i]);
+            return FALSE;
+        }
+        switch(pPath->pFlags[i])
+        {
+            case PT_MOVETO:
+                if(numStrokes > 0)
+                {
+                    pStrokes[numStrokes - 1]->state = PATH_Closed;
+                }
+                numStrokes++;
+                j = 0;
+                ExFreePool(pStrokes);
+                pStrokes = ExAllocatePoolWithTag(PagedPool, numStrokes * sizeof(PPATH), TAG_PATH);
+                pStrokes[numStrokes - 1] = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+
+                PATH_InitGdiPath(pStrokes[numStrokes - 1]);
+                pStrokes[numStrokes - 1]->state = PATH_Open;
+            case PT_LINETO:
+            case (PT_LINETO | PT_CLOSEFIGURE):
+                point.x = pPath->pPoints[i].x;
+                point.y = pPath->pPoints[i].y;
+                PATH_AddEntry(pStrokes[numStrokes - 1], &point, pPath->pFlags[i]);
+                break;
+            case PT_BEZIERTO:
+                /* should never happen because of the FlattenPath call */
+                DPRINT1("Should never happen\n");
+                break;
+            default:
+                DPRINT1("Got path flag %c\n", pPath->pFlags[i]);
+                return FALSE;
+        }
     }
 
-    /* Copy old arrays to new arrays and discard old arrays */
-    if(pPath->pPoints)
-    {
-      ASSERT(pPath->pFlags);
+    pNewPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);  
+    PATH_InitGdiPath(pNewPath);
+    pNewPath->state = PATH_Open;
 
-      memcpy(pPointsNew, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
-      memcpy(pFlagsNew, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
+    for(i = 0; i < numStrokes; i++)
+    {
+        pUpPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+        PATH_InitGdiPath(pUpPath);
+        pUpPath->state = PATH_Open;
+        pDownPath = ExAllocatePoolWithTag(PagedPool, sizeof(PATH), TAG_PATH);
+        PATH_InitGdiPath(pDownPath);
+        pDownPath->state = PATH_Open;
+
+        for(j = 0; j < pStrokes[i]->numEntriesUsed; j++)
+        {
+            /* Beginning or end of the path if not closed */
+            if((!(pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) && (j == 0 || j == pStrokes[i]->numEntriesUsed - 1) )
+            {
+                /* Compute segment angle */
+                double xo, yo, xa, ya, theta;
+                POINT pt;
+                FLOAT_POINT corners[2];
+                if(j == 0)
+                {
+                    xo = pStrokes[i]->pPoints[j].x;
+                    yo = pStrokes[i]->pPoints[j].y;
+                    xa = pStrokes[i]->pPoints[1].x;
+                    ya = pStrokes[i]->pPoints[1].y;
+                }
+                else
+                {
+                    xa = pStrokes[i]->pPoints[j - 1].x;
+                    ya = pStrokes[i]->pPoints[j - 1].y;
+                    xo = pStrokes[i]->pPoints[j].x;
+                    yo = pStrokes[i]->pPoints[j].y;
+                }
+                theta = atan2( ya - yo, xa - xo );
+                switch(endcap)
+                {
+                    case PS_ENDCAP_SQUARE :
+                        pt.x = xo + round(sqrt(2) * penWidthOut * cos(M_PI_4 + theta));
+                        pt.y = yo + round(sqrt(2) * penWidthOut * sin(M_PI_4 + theta));
+                        PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO) );
+                        pt.x = xo + round(sqrt(2) * penWidthIn * cos(- M_PI_4 + theta));
+                        pt.y = yo + round(sqrt(2) * penWidthIn * sin(- M_PI_4 + theta));
+                        PATH_AddEntry(pUpPath, &pt, PT_LINETO);
+                        break;
+                    case PS_ENDCAP_FLAT :
+                        pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+                        pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+                        PATH_AddEntry(pUpPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
+                        pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
+                        pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
+                        PATH_AddEntry(pUpPath, &pt, PT_LINETO);
+                        break;
+                    case PS_ENDCAP_ROUND :
+                    default :
+                        corners[0].x = xo - penWidthIn;
+                        corners[0].y = yo - penWidthIn;
+                        corners[1].x = xo + penWidthOut;
+                        corners[1].y = yo + penWidthOut;
+                        PATH_DoArcPart(pUpPath ,corners, theta + M_PI_2 , theta + 3 * M_PI_4, (j == 0 ? PT_MOVETO : FALSE));
+                        PATH_DoArcPart(pUpPath ,corners, theta + 3 * M_PI_4 , theta + M_PI, FALSE);
+                        PATH_DoArcPart(pUpPath ,corners, theta + M_PI, theta +  5 * M_PI_4, FALSE);
+                        PATH_DoArcPart(pUpPath ,corners, theta + 5 * M_PI_4 , theta + 3 * M_PI_2, FALSE);
+                        break;
+                }
+            }
+            /* Corpse of the path */
+            else
+            {
+                /* Compute angle */
+                INT previous, next;
+                double xa, ya, xb, yb, xo, yo;
+                double alpha, theta, miterWidth;
+                DWORD _joint = joint;
+                POINT pt;
+               PPATH pInsidePath, pOutsidePath;
+                if(j > 0 && j < pStrokes[i]->numEntriesUsed - 1)
+                {
+                    previous = j - 1;
+                    next = j + 1;
+                }
+                else if (j == 0)
+                {
+                    previous = pStrokes[i]->numEntriesUsed - 1;
+                    next = j + 1;
+                }
+                else
+                {
+                    previous = j - 1;
+                    next = 0;
+                }
+                xo = pStrokes[i]->pPoints[j].x;
+                yo = pStrokes[i]->pPoints[j].y;
+                xa = pStrokes[i]->pPoints[previous].x;
+                ya = pStrokes[i]->pPoints[previous].y;
+                xb = pStrokes[i]->pPoints[next].x;
+                yb = pStrokes[i]->pPoints[next].y;
+                theta = atan2( yo - ya, xo - xa );
+                alpha = atan2( yb - yo, xb - xo ) - theta;
+                if (alpha > 0) alpha -= M_PI;
+                else alpha += M_PI;
+                if(_joint == PS_JOIN_MITER && dc->DcLevel.laPath.eMiterLimit < fabs(1 / sin(alpha/2)))
+                {
+                    _joint = PS_JOIN_BEVEL;
+                }
+                if(alpha > 0)
+                {
+                    pInsidePath = pUpPath;
+                    pOutsidePath = pDownPath;
+                }
+                else if(alpha < 0)
+                {
+                    pInsidePath = pDownPath;
+                    pOutsidePath = pUpPath;
+                }
+                else
+                {
+                    continue;
+                }
+                /* Inside angle points */
+                if(alpha > 0)
+                {
+                    pt.x = xo - round( penWidthIn * cos(theta + M_PI_2) );
+                    pt.y = yo - round( penWidthIn * sin(theta + M_PI_2) );
+                }
+                else
+                {
+                    pt.x = xo + round( penWidthIn * cos(theta + M_PI_2) );
+                    pt.y = yo + round( penWidthIn * sin(theta + M_PI_2) );
+                }
+                PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
+                if(alpha > 0)
+                {
+                    pt.x = xo + round( penWidthIn * cos(M_PI_2 + alpha + theta) );
+                    pt.y = yo + round( penWidthIn * sin(M_PI_2 + alpha + theta) );
+                }
+                else
+                {
+                    pt.x = xo - round( penWidthIn * cos(M_PI_2 + alpha + theta) );
+                    pt.y = yo - round( penWidthIn * sin(M_PI_2 + alpha + theta) );
+                }
+                PATH_AddEntry(pInsidePath, &pt, PT_LINETO);
+                /* Outside angle point */
+                switch(_joint)
+                {
+                     case PS_JOIN_MITER :
+                        miterWidth = fabs(penWidthOut / cos(M_PI_2 - fabs(alpha) / 2));
+                        pt.x = xo + round( miterWidth * cos(theta + alpha / 2) );
+                        pt.y = yo + round( miterWidth * sin(theta + alpha / 2) );
+                        PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+                        break;
+                    case PS_JOIN_BEVEL :
+                        if(alpha > 0)
+                        {
+                            pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+                            pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+                        }
+                        else
+                        {
+                            pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
+                            pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
+                        }
+                        PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+                        if(alpha > 0)
+                        {
+                            pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+                            pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+                        }
+                        else
+                        {
+                            pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+                            pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+                        }
+                        PATH_AddEntry(pOutsidePath, &pt, PT_LINETO);
+                        break;
+                    case PS_JOIN_ROUND :
+                    default :
+                        if(alpha > 0)
+                        {
+                            pt.x = xo + round( penWidthOut * cos(theta + M_PI_2) );
+                            pt.y = yo + round( penWidthOut * sin(theta + M_PI_2) );
+                        }
+                        else
+                        {
+                            pt.x = xo - round( penWidthOut * cos(theta + M_PI_2) );
+                            pt.y = yo - round( penWidthOut * sin(theta + M_PI_2) );
+                        }
+                        PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+                        pt.x = xo + round( penWidthOut * cos(theta + alpha / 2) );
+                        pt.y = yo + round( penWidthOut * sin(theta + alpha / 2) );
+                        PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+                        if(alpha > 0)
+                        {
+                            pt.x = xo - round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+                            pt.y = yo - round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+                        }
+                        else
+                        {
+                            pt.x = xo + round( penWidthOut * cos(M_PI_2 + alpha + theta) );
+                            pt.y = yo + round( penWidthOut * sin(M_PI_2 + alpha + theta) );
+                        }
+                        PATH_AddEntry(pOutsidePath, &pt, PT_BEZIERTO);
+                        break;
+                }
+            }
+        }
+        for(j = 0; j < pUpPath->numEntriesUsed; j++)
+        {
+            POINT pt;
+            pt.x = pUpPath->pPoints[j].x;
+            pt.y = pUpPath->pPoints[j].y;
+            PATH_AddEntry(pNewPath, &pt, (j == 0 ? PT_MOVETO : PT_LINETO));
+        }
+        for(j = 0; j < pDownPath->numEntriesUsed; j++)
+        {
+            POINT pt;
+            pt.x = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].x;
+            pt.y = pDownPath->pPoints[pDownPath->numEntriesUsed - j - 1].y;
+            PATH_AddEntry(pNewPath, &pt, ( (j == 0 && (pStrokes[i]->pFlags[pStrokes[i]->numEntriesUsed - 1] & PT_CLOSEFIGURE)) ? PT_MOVETO : PT_LINETO));
+        }
 
-      ExFreePool(pPath->pPoints);
-      ExFreePool(pPath->pFlags);
+        PATH_DestroyGdiPath(pStrokes[i]);
+        ExFreePool(pStrokes[i]);
+        PATH_DestroyGdiPath(pUpPath);
+        ExFreePool(pUpPath);
+        PATH_DestroyGdiPath(pDownPath);
+        ExFreePool(pDownPath);
     }
-    pPath->pPoints=pPointsNew;
-    pPath->pFlags=pFlagsNew;
-    pPath->numEntriesAllocated=numEntriesToAllocate;
-  }
+    ExFreePool(pStrokes);
 
-  return TRUE;
+    pNewPath->state = PATH_Closed;
+    if (!(ret = PATH_AssignGdiPath(pPath, pNewPath)))
+        DPRINT1("Assign path failed\n");
+    PATH_DestroyGdiPath(pNewPath);
+    ExFreePool(pNewPath);
+    return ret;
 }
 
-/* PATH_DoArcPart
- *
- * Creates a Bezier spline that corresponds to part of an arc and appends the
- * corresponding points to the path. The start and end angles are passed in
- * "angleStart" and "angleEnd"; these angles should span a quarter circle
- * at most. If "addMoveTo" is true, a PT_MOVETO entry for the first control
- * point is added to the path; otherwise, it is assumed that the current
- * position is equal to the first control point.
+
+
+/***********************************************************************
+ * Exported functions
  */
+
 BOOL
-FASTCALL
-PATH_DoArcPart ( GdiPath *pPath, FLOAT_POINT corners[],
-   double angleStart, double angleEnd, BOOL addMoveTo )
+STDCALL
+NtGdiAbortPath(HDC  hDC)
 {
-  double  halfAngle, a;
-  double  xNorm[4], yNorm[4];
-  POINT point;
-  int i;
+  PPATH pPath;
+  PDC dc = DC_LockDc ( hDC );
+  if ( !dc )
+  {
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return FALSE;
+  }
 
-  ASSERT(fabs(angleEnd-angleStart)<=M_PI_2);
+  pPath = PATH_LockPath(dc->DcLevel.hPath);
+  {
+      DC_UnlockDc(dc);
+      return FALSE;
+  }
 
-  /* FIXME: Is there an easier way of computing this? */
+  PATH_EmptyPath(pPath);
 
-  /* Compute control points */
-  halfAngle=(angleEnd-angleStart)/2.0;
-  if(fabs(halfAngle)>1e-8)
+  PATH_UnlockPath(pPath);
+  DC_UnlockDc ( dc );
+  return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiBeginPath( HDC  hDC )
+{
+  PPATH pPath;
+  PDC dc;
+
+  dc = DC_LockDc ( hDC );
+  if ( !dc )
   {
-    a=4.0/3.0*(1-cos(halfAngle))/sin(halfAngle);
-    xNorm[0]=cos(angleStart);
-    yNorm[0]=sin(angleStart);
-    xNorm[1]=xNorm[0] - a*yNorm[0];
-    yNorm[1]=yNorm[0] + a*xNorm[0];
-    xNorm[3]=cos(angleEnd);
-    yNorm[3]=sin(angleEnd);
-    xNorm[2]=xNorm[3] + a*yNorm[3];
-    yNorm[2]=yNorm[3] - a*xNorm[3];
-  } else
-    for(i=0; i<4; i++)
-    {
-      xNorm[i]=cos(angleStart);
-      yNorm[i]=sin(angleStart);
-    }
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return FALSE;
+  }
 
-  /* Add starting point to path if desired */
-  if(addMoveTo)
+  /* If path is already open, do nothing. Check if not Save DC state */
+    if ((dc->DcLevel.flPath & DCPATH_ACTIVE) && !(dc->DcLevel.flPath & DCPATH_SAVE))
   {
-    PATH_ScaleNormalizedPoint(corners, xNorm[0], yNorm[0], &point);
-    if(!PATH_AddEntry(pPath, &point, PT_MOVETO))
-      return FALSE;
+     DC_UnlockDc ( dc );
+     return TRUE;
   }
 
-  /* Add remaining control points */
-  for(i=1; i<4; i++)
+  if ( dc->DcLevel.hPath )
   {
-    PATH_ScaleNormalizedPoint(corners, xNorm[i], yNorm[i], &point);
-    if(!PATH_AddEntry(pPath, &point, PT_BEZIERTO))
-      return FALSE;
+     DPRINT1("BeginPath 1 0x%x\n", dc->DcLevel.hPath);
+     if ( !(dc->DcLevel.flPath & DCPATH_SAVE) )
+     {  // Remove previous handle.
+        if (!PATH_Delete(dc->DcLevel.hPath))
+        {
+           DC_UnlockDc ( dc );
+           return FALSE;
+        }
+     }
+     else
+     {  // Clear flags and Handle.
+        dc->DcLevel.flPath &= ~(DCPATH_SAVE|DCPATH_ACTIVE);
+        dc->DcLevel.hPath = NULL;
+     }
   }
+  pPath = PATH_AllocPathWithHandle();
+  if (!pPath)
+  {
+     SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+     return FALSE;
+  }
+  dc->DcLevel.flPath |= DCPATH_ACTIVE; // Set active ASAP!
 
-  return TRUE;
-}
+  dc->DcLevel.hPath = pPath->BaseObject.hHmgr;
 
-/* PATH_ScaleNormalizedPoint
- *
- * Scales a normalized point (x, y) with respect to the box whose corners are
- * passed in "corners". The point is stored in "*pPoint". The normalized
- * coordinates (-1.0, -1.0) correspond to corners[0], the coordinates
- * (1.0, 1.0) correspond to corners[1].
- */
-VOID
-FASTCALL
-PATH_ScaleNormalizedPoint ( FLOAT_POINT corners[], double x,
-   double y, POINT *pPoint )
+  DPRINT1("BeginPath 2 h 0x%x p 0x%x\n", dc->DcLevel.hPath, pPath);
+  // Path handles are shared. Also due to recursion with in the same thread.
+  GDIOBJ_UnlockObjByPtr((POBJ)pPath);       // Unlock
+  pPath = PATH_LockPath(dc->DcLevel.hPath); // Share Lock.
+
+  /* Make sure that path is empty */
+  PATH_EmptyPath( pPath );
+
+  /* Initialize variables for new path */
+  pPath->newStroke = TRUE;
+  pPath->state = PATH_Open;
+
+  PATH_UnlockPath(pPath);
+  DC_UnlockDc ( dc );
+  return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiCloseFigure(HDC hDC)
 {
-  ASSERT ( corners );
-  ASSERT ( pPoint );
-  pPoint->x=GDI_ROUND( (double)corners[0].x + (double)(corners[1].x-corners[0].x)*0.5*(x+1.0) );
-  pPoint->y=GDI_ROUND( (double)corners[0].y + (double)(corners[1].y-corners[0].y)*0.5*(y+1.0) );
+  BOOL Ret = FALSE; // default to failure
+  PDC pDc;
+  PPATH pPath;
+
+  DPRINT("Enter %s\n", __FUNCTION__);
+
+  pDc = DC_LockDc(hDC);
+  if (!pDc)
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }   
+  pPath = PATH_LockPath( pDc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc(pDc);
+     return FALSE;
+  }
+
+  if (pPath->state==PATH_Open)
+  {
+     IntGdiCloseFigure(pPath);
+     Ret = TRUE;
+  }
+  else
+  {
+     // FIXME: check if lasterror is set correctly
+     SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+  }
+
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc(pDc);
+  return Ret;
 }
 
-/* PATH_NormalizePoint
- *
- * Normalizes a point with respect to the box whose corners are passed in
- * corners. The normalized coordinates are stored in *pX and *pY.
- */
-VOID
-FASTCALL
-PATH_NormalizePoint ( FLOAT_POINT corners[],
-   const FLOAT_POINT *pPoint,
-   double *pX, double *pY)
+BOOL
+STDCALL
+NtGdiEndPath(HDC  hDC)
 {
-  ASSERT ( corners );
-  ASSERT ( pPoint );
-  ASSERT ( pX );
-  ASSERT ( pY );
-  *pX=(double)(pPoint->x-corners[0].x)/(double)(corners[1].x-corners[0].x) * 2.0 - 1.0;
-  *pY=(double)(pPoint->y-corners[0].y)/(double)(corners[1].y-corners[0].y) * 2.0 - 1.0;
+  BOOL ret = TRUE;
+  PPATH pPath;
+  PDC dc = DC_LockDc ( hDC );
+
+  if ( !dc )
+  {
+     SetLastWin32Error(ERROR_INVALID_HANDLE);
+     return FALSE;
+  }
+
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( dc );
+     return FALSE;
+  }
+  /* Check that path is currently being constructed */
+  if ( (pPath->state != PATH_Open) || !(dc->DcLevel.flPath & DCPATH_ACTIVE) )
+  {
+    DPRINT1("EndPath ERROR! 0x%x\n", dc->DcLevel.hPath);
+    SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+    ret = FALSE;
+  }
+  /* Set flag to indicate that path is finished */
+  else
+  {
+     DPRINT1("EndPath 0x%x\n", dc->DcLevel.hPath);
+     pPath->state = PATH_Closed;
+     dc->DcLevel.flPath &= ~DCPATH_ACTIVE;
+  }
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc ( dc );
+  return ret;
 }
 
+BOOL
+STDCALL
+NtGdiFillPath(HDC  hDC)
+{
+  BOOL ret = TRUE;
+  PPATH pPath;
+  PDC dc = DC_LockDc ( hDC );
+  if ( !dc )
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( dc );
+     return FALSE;
+  }
 
-BOOL FASTCALL PATH_StrokePath(DC *dc, GdiPath *pPath)
+  ret = PATH_FillPath( dc, pPath );
+  if ( ret )
+  {
+    /* FIXME: Should the path be emptied even if conversion
+       failed? */
+    PATH_EmptyPath( pPath );
+  }
+
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc ( dc );
+  return ret;
+}
+
+BOOL
+STDCALL
+NtGdiFlattenPath(HDC  hDC)
 {
-    BOOL ret = FALSE;
-    INT i=0;
-    INT nLinePts, nAlloc;
-    POINT *pLinePts = NULL;
-    POINT ptViewportOrg, ptWindowOrg;
-    SIZE szViewportExt, szWindowExt;
-    DWORD mapMode, graphicsMode;
-    XFORM xform;
-    PDC_ATTR Dc_Attr = dc->pDc_Attr;
+   BOOL Ret = FALSE;
+   DC *pDc;
+   PPATH pPath;
 
-    DPRINT("Enter %s\n", __FUNCTION__);
+   DPRINT("Enter %s\n", __FUNCTION__);
 
-    if(pPath->state != PATH_Closed)
-        return FALSE;
-    if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-    /* Save the mapping mode info */
-    mapMode = Dc_Attr->iMapMode;
-    IntGetViewportExtEx(dc, &szViewportExt);
-    IntGetViewportOrgEx(dc, &ptViewportOrg);
-    IntGetWindowExtEx(dc, &szWindowExt);
-    IntGetWindowOrgEx(dc, &ptWindowOrg);
-    xform = dc->DcLevel.xformWorld2Wnd;
+   pDc = DC_LockDc(hDC);
+   if (!pDc)
+   {
+      SetLastWin32Error(ERROR_INVALID_HANDLE);  
+      return FALSE;
+   }
 
-    /* Set MM_TEXT */
-    Dc_Attr->iMapMode = MM_TEXT;
-    Dc_Attr->ptlViewportOrg.x = 0;
-    Dc_Attr->ptlViewportOrg.y = 0;
-    Dc_Attr->ptlWindowOrg.x = 0;
-    Dc_Attr->ptlWindowOrg.y = 0;
-    graphicsMode = Dc_Attr->iGraphicsMode;
-    Dc_Attr->iGraphicsMode = GM_ADVANCED;
-    IntGdiModifyWorldTransform(dc, &xform, MWT_IDENTITY);
-    Dc_Attr->iGraphicsMode = graphicsMode;
+   pPath = PATH_LockPath( pDc->DcLevel.hPath );
+   if (!pPath)
+   {
+      DC_UnlockDc ( pDc );
+      return FALSE;
+   }
+   if (pPath->state == PATH_Open)
+      Ret = PATH_FlattenPath(pPath);
 
-    /* Allocate enough memory for the worst case without beziers (one PT_MOVETO
-     * and the rest PT_LINETO with PT_CLOSEFIGURE at the end) plus some buffer
-     * space in case we get one to keep the number of reallocations small. */
-    nAlloc = pPath->numEntriesUsed + 1 + 300;
-    pLinePts = ExAllocatePoolWithTag(PagedPool, nAlloc * sizeof(POINT), TAG_PATH);
-    if(!pLinePts)
-    {
-        DPRINT1("Can't allocate pool!\n");
-        SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
-        goto end;
-    }
-    nLinePts = 0;
+   PATH_UnlockPath( pPath );
+   DC_UnlockDc(pDc);
+   return Ret;
+}
 
-    for(i = 0; i < pPath->numEntriesUsed; i++)
-    {
-        if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE))
-                && (pPath->pFlags[i] != PT_MOVETO))
-        {
-            DPRINT1("Expected PT_MOVETO %s, got path flag %d\n",
-                i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
-                (INT)pPath->pFlags[i]);
-                goto end;
-        }
 
-        switch(pPath->pFlags[i])
-        {
-        case PT_MOVETO:
-            DPRINT("Got PT_MOVETO (%ld, %ld)\n",
-                pPath->pPoints[i].x, pPath->pPoints[i].y);
-            if(nLinePts >= 2) IntGdiPolyline(dc, pLinePts, nLinePts);
-            nLinePts = 0;
-            pLinePts[nLinePts++] = pPath->pPoints[i];
-            break;
-        case PT_LINETO:
-        case (PT_LINETO | PT_CLOSEFIGURE):
-            DPRINT("Got PT_LINETO (%ld, %ld)\n",
-              pPath->pPoints[i].x, pPath->pPoints[i].y);
-            pLinePts[nLinePts++] = pPath->pPoints[i];
-            break;
-        case PT_BEZIERTO:
-            DPRINT("Got PT_BEZIERTO\n");
-            if(pPath->pFlags[i+1] != PT_BEZIERTO ||
-               (pPath->pFlags[i+2] & ~PT_CLOSEFIGURE) != PT_BEZIERTO)
-            {
-                DPRINT1("Path didn't contain 3 successive PT_BEZIERTOs\n");
-                ret = FALSE;
-                goto end;
-            }
-            else
-            {
-                INT nBzrPts, nMinAlloc;
-                POINT *pBzrPts = GDI_Bezier(&pPath->pPoints[i-1], 4, &nBzrPts);
-                /* Make sure we have allocated enough memory for the lines of
-                 * this bezier and the rest of the path, assuming we won't get
-                 * another one (since we won't reallocate again then). */
-                nMinAlloc = nLinePts + (pPath->numEntriesUsed - i) + nBzrPts;
-                if(nAlloc < nMinAlloc)
-                {
-                    // Reallocate memory
+BOOL
+APIENTRY
+NtGdiGetMiterLimit(
+    IN HDC hdc,
+    OUT PDWORD pdwOut)
+{
+  DC *pDc;
+  gxf_long worker;
+  NTSTATUS Status = STATUS_SUCCESS;
 
-                    POINT *Realloc = NULL;
-                    nAlloc = nMinAlloc * 2;
+  if (!(pDc = DC_LockDc(hdc)))
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
 
-                    Realloc = ExAllocatePoolWithTag(PagedPool,
-                        nAlloc * sizeof(POINT),
-                        TAG_PATH);
+  worker.f = pDc->DcLevel.laPath.eMiterLimit;
 
-                    if(!Realloc)
-                    {
-                        DPRINT1("Can't allocate pool!\n");
-                        goto end;
-                    }
+  if (pdwOut)
+  {
+      _SEH_TRY
+      {
+          ProbeForWrite(pdwOut,
+                 sizeof(DWORD),
+                             1);
+          *pdwOut = worker.l;
+      }
+      _SEH_HANDLE
+      {
+          Status = _SEH_GetExceptionCode();
+      }
+       _SEH_END;
+      if (!NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         DC_UnlockDc(pDc);
+         return FALSE;
+      }
+  }
 
-                    memcpy(Realloc, pLinePts, nLinePts*sizeof(POINT));
-                    ExFreePool(pLinePts);
-                    pLinePts = Realloc;
-                }
-                memcpy(&pLinePts[nLinePts], &pBzrPts[1], (nBzrPts - 1) * sizeof(POINT));
-                nLinePts += nBzrPts - 1;
-                ExFreePool(pBzrPts);
-                i += 2;
-            }
-            break;
-        default:
-            DPRINT1("Got path flag %d (not supported)\n", (INT)pPath->pFlags[i]);
-            goto end;
-        }
+  DC_UnlockDc(pDc);
+  return TRUE;
 
-        if(pPath->pFlags[i] & PT_CLOSEFIGURE)
-        {
-            pLinePts[nLinePts++] = pLinePts[0];
-        }
-    }//for
+}
 
-    if(nLinePts >= 2)
-        IntGdiPolyline(dc, pLinePts, nLinePts);
+INT
+STDCALL
+NtGdiGetPath(
+   HDC hDC,
+   LPPOINT Points,
+   LPBYTE Types,
+   INT nSize)
+{
+  INT ret = -1;
+  PPATH pPath;
 
-    ret = TRUE;
+  DC *dc = DC_LockDc(hDC);
+  if (!dc)
+  {
+     DPRINT1("Can't lock dc!\n");
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return -1;
+  }
 
-end:
-    if(pLinePts)ExFreePool(pLinePts);
+  pPath = PATH_LockPath( dc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( dc );
+     return -1;
+  }
 
-    /* Restore the old mapping mode */
-    Dc_Attr->iMapMode =  mapMode;
-    Dc_Attr->szlWindowExt.cx = szWindowExt.cx;
-    Dc_Attr->szlWindowExt.cy = szWindowExt.cy;
-    Dc_Attr->ptlWindowOrg.x = ptWindowOrg.x;
-    Dc_Attr->ptlWindowOrg.y = ptWindowOrg.y;
+  if (pPath->state != PATH_Closed)
+  {
+     SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+     goto done;
+  }
 
-    Dc_Attr->szlViewportExt.cx = szViewportExt.cx;
-    Dc_Attr->szlViewportExt.cy = szViewportExt.cy;
-    Dc_Attr->ptlViewportOrg.x = ptViewportOrg.x;
-    Dc_Attr->ptlViewportOrg.y = ptViewportOrg.y;
+  if (nSize==0)
+  {
+     ret = pPath->numEntriesUsed;
+  }
+  else if(nSize<pPath->numEntriesUsed)
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     goto done;
+  }
+  else
+  {
+      _SEH_TRY
+      {
+         memcpy(Points, pPath->pPoints, sizeof(POINT)*pPath->numEntriesUsed);
+         memcpy(Types, pPath->pFlags, sizeof(BYTE)*pPath->numEntriesUsed);
 
-    /* Restore the world transform */
-    dc->DcLevel.xformWorld2Wnd = xform;
+         /* Convert the points to logical coordinates */
+         IntDPtoLP(dc, Points, pPath->numEntriesUsed);
 
-    /* If we've moved the current point then get its new position
-       which will be in device (MM_TEXT) co-ords, convert it to
-       logical co-ords and re-set it.  This basically updates
-       dc->CurPosX|Y so that their values are in the correct mapping
-       mode.
-    */
-    if(i > 0)
-    {
-        POINT pt;
-        IntGetCurrentPositionEx(dc, &pt);
-        IntDPtoLP(dc, &pt, 1);
-        IntGdiMoveToEx(dc, pt.x, pt.y, NULL);
-    }
-    DPRINT("Leave %s, ret=%d\n", __FUNCTION__, ret);
-    return ret;
+         ret = pPath->numEntriesUsed;
+      }
+      _SEH_HANDLE
+      {
+         SetLastNtError(_SEH_GetExceptionCode());
+      }
+      _SEH_END
+  }
+
+done:
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc(dc);
+  return ret;
+}
+
+HRGN
+STDCALL
+NtGdiPathToRegion(HDC  hDC)
+{
+  PPATH pPath;
+  HRGN  hrgnRval = 0;
+  DC *pDc;
+  PDC_ATTR Dc_Attr;
+
+  DPRINT("Enter %s\n", __FUNCTION__);
+
+  pDc = DC_LockDc(hDC);
+  if (!pDc)
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return NULL;
+  }
+
+  Dc_Attr = pDc->pDc_Attr;
+  if(!Dc_Attr) Dc_Attr = &pDc->Dc_Attr;
+
+  pPath = PATH_LockPath( pDc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( pDc );
+     return NULL;
+  }
+
+  if (pPath->state!=PATH_Closed)
+  {
+     //FIXME: check that setlasterror is being called correctly
+     SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+  }
+  else
+  {
+     /* FIXME: Should we empty the path even if conversion failed? */
+     if(PATH_PathToRegion(pPath, Dc_Attr->jFillMode, &hrgnRval))
+          PATH_EmptyPath(pPath);
+  }
+
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc(pDc);
+  return hrgnRval;
+}
+
+BOOL
+APIENTRY
+NtGdiSetMiterLimit(
+    IN HDC hdc,
+    IN DWORD dwNew,
+    IN OUT OPTIONAL PDWORD pdwOut)
+{
+  DC *pDc;
+  gxf_long worker, worker1;
+  NTSTATUS Status = STATUS_SUCCESS;
+
+  if (!(pDc = DC_LockDc(hdc)))
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+
+  worker.l  = dwNew;
+  worker1.f = pDc->DcLevel.laPath.eMiterLimit;
+  pDc->DcLevel.laPath.eMiterLimit = worker.f;
+
+  if (pdwOut)
+  {
+      _SEH_TRY
+      {
+          ProbeForWrite(pdwOut,
+                 sizeof(DWORD),
+                             1);
+          *pdwOut = worker1.l;
+      }
+      _SEH_HANDLE
+      {
+          Status = _SEH_GetExceptionCode();
+      }
+       _SEH_END;
+      if (!NT_SUCCESS(Status))
+      {
+         SetLastNtError(Status);
+         DC_UnlockDc(pDc);
+         return FALSE;
+      }
+  }
+
+  DC_UnlockDc(pDc);
+  return TRUE;
+}
+
+BOOL
+STDCALL
+NtGdiStrokeAndFillPath(HDC hDC)
+{
+  DC *pDc;
+  PPATH pPath;
+  BOOL bRet = FALSE;
+
+  DPRINT1("Enter %s\n", __FUNCTION__);
+
+  if (!(pDc = DC_LockDc(hDC)))
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+  pPath = PATH_LockPath( pDc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( pDc );
+     return FALSE;
+  }
+  bRet = PATH_FillPath(pDc, pPath);
+  if (bRet) bRet = PATH_StrokePath(pDc, pPath);
+  if (bRet) PATH_EmptyPath(pPath);
+
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc(pDc);
+  return bRet;
+}
+
+BOOL
+STDCALL
+NtGdiStrokePath(HDC hDC)
+{
+  DC *pDc;
+  PPATH pPath;
+  BOOL bRet = FALSE;
+
+  DPRINT("Enter %s\n", __FUNCTION__);
+
+  if (!(pDc = DC_LockDc(hDC)))
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+  pPath = PATH_LockPath( pDc->DcLevel.hPath );
+  if (!pPath)
+  {
+     DC_UnlockDc ( pDc );
+     return FALSE;
+  }
+
+  bRet = PATH_StrokePath(pDc, pPath);
+  PATH_EmptyPath(pPath);
+
+  PATH_UnlockPath( pPath );
+  DC_UnlockDc(pDc);
+  return bRet;
+}
+
+BOOL
+STDCALL
+NtGdiWidenPath(HDC  hDC)
+{
+  BOOL Ret;
+  PDC pdc = DC_LockDc ( hDC );    
+  if ( !pdc )
+  {
+     SetLastWin32Error(ERROR_INVALID_PARAMETER);
+     return FALSE;
+  }
+  Ret = PATH_WidenPath(pdc);
+  DC_UnlockDc ( pdc );
+  return Ret;
+}
+
+BOOL
+STDCALL
+NtGdiSelectClipPath(HDC  hDC,
+                   int  Mode)
+{
+ HRGN  hrgnPath;
+ PPATH pPath;
+ BOOL  success = FALSE;
+ PDC_ATTR Dc_Attr;
+ PDC dc = DC_LockDc ( hDC );
+ if ( !dc )
+ {
+    SetLastWin32Error(ERROR_INVALID_PARAMETER);
+    return FALSE;
+ }
+
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+ pPath = PATH_LockPath( dc->DcLevel.hPath );
+ if (!pPath)
+ {
+    DC_UnlockDc ( dc );
+    return FALSE;
+ }
+ /* Check that path is closed */
+ if( pPath->state != PATH_Closed )
+ {
+   SetLastWin32Error(ERROR_CAN_NOT_COMPLETE);
+   return FALSE;
+ }
+ /* Construct a region from the path */
+ else if( PATH_PathToRegion( pPath, Dc_Attr->jFillMode, &hrgnPath ) )
+ {
+   success = GdiExtSelectClipRgn( dc, hrgnPath, Mode ) != ERROR;
+   NtGdiDeleteObject( hrgnPath );
+
+   /* Empty the path */
+   if( success )
+     PATH_EmptyPath( pPath);
+   /* FIXME: Should this function delete the path even if it failed? */
+ }
+ PATH_UnlockPath( pPath );
+ DC_UnlockDc ( dc );
+ return success;
 }
 
 /* EOF */
index 3375543..1b8b1a7 100644 (file)
@@ -3648,7 +3648,7 @@ REGION_CreateETandAET(
 }
 
 HRGN FASTCALL
-IntCreatePolyPolgonRgn(
+IntCreatePolyPolygonRgn(
     POINT *Pts,
     INT *Count,
     INT nbpolygons,
@@ -3972,7 +3972,7 @@ GdiCreatePolyPolygonRgn(
     }
 
     /* now we're ready to calculate the region safely */
-    hRgn = IntCreatePolyPolgonRgn(Safept, SafePolyCounts, Count, PolyFillMode);
+    hRgn = IntCreatePolyPolygonRgn(Safept, SafePolyCounts, Count, PolyFillMode);
 
     ExFreePool(Safept);
     ExFreePool(SafePolyCounts);