gdi32:WidenPath

Laurent Vromman laurent at vromman.org
Sat Jan 27 15:25:04 CST 2007


Hi,

Here is a try for the function gdi32:WidenPath. The function is
partially implemented. It doesn't manage user style brush, and the
path's corners can be improved.

My devel skills are not perfect and there are probably many things to
improve in this patch. Anyway, this function works with two Windows
applications which use WidenPath. It is a good beginning for me.

Laurent Vromman

(The same with the patch attached to the mail)
-------------- next part --------------
diff --git a/dlls/gdi32/path.c b/dlls/gdi32/path.c
index 306ed37..d9ccbb3 100644
--- a/dlls/gdi32/path.c
+++ b/dlls/gdi32/path.c
@@ -1823,6 +1823,14 @@ BOOL WINAPI StrokePath(HDC hdc)
 /*******************************************************************
  *      WidenPath [GDI32.@]
  *
+ *   Redefines the current path as the area that would be painted if the path were stroked using the pen currently selected into the given device context.
+ *
+ *   PARAMS
+ *    hdc    [I] Handle to a device context that contains a closed path.
+ *
+ *   RETURNS
+ *     Success: TRUE. The path is updated with the new computed path.
+ *     Failure: FALSE.
  *
  */
 BOOL WINAPI WidenPath(HDC hdc)
@@ -1833,9 +1841,188 @@ BOOL WINAPI WidenPath(HDC hdc)
    if(!dc) return FALSE;
 
    if(dc->funcs->pWidenPath)
-     ret = dc->funcs->pWidenPath(dc->physDev);
-
-   FIXME("stub\n");
+      ret = dc->funcs->pWidenPath(dc->physDev);
+   else {
+      ret = PATH_WidenPath(hdc);
+   }
    GDI_ReleaseObj( hdc );
+   FIXME("partially implemented\n");
    return ret;
 }
+
+static BOOL PATH_WidenPath(HDC hdc) 
+{
+    INT i, j, numStrokes, nLinePts, penWidth, penWidthIn, penWidthOut, size;
+    DC *dc;
+    BOOL ret = FALSE;
+    GdiPath *pPath, *pNewPath, **pStrokes, *pUpPath, *pDownPath;
+    HPEN hPen;
+    EXTLOGPEN *elp;
+    FLOAT fCos, fSin, nPente;
+
+    dc = DC_GetDCPtr( hdc );
+    pPath = &dc->path;
+
+    PATH_FlattenPath(pPath);
+
+    if(pPath->state != PATH_Closed) {
+       ERR("Path Closed\n");
+       return FALSE;
+    }
+
+    hPen = SelectObject(hdc, GetStockObject(DC_PEN));
+
+    size = GetObjectW( hPen, 0, NULL );
+
+    if (!size) return FALSE;
+
+    elp = HeapAlloc( GetProcessHeap(), 0, size );
+
+    GetObjectW( hPen, size, elp );
+    /* FIXME: add support for user style pens */
+    penWidth = elp->elpWidth;
+    HeapFree( GetProcessHeap(), 0, elp );
+
+    /* FIXME : If extPen, use the shape on corners */
+    penWidthIn = penWidth / 2;
+    penWidthOut = penWidth / 2;
+    if(penWidthIn + penWidthOut < penWidth)
+        penWidthOut++;
+
+    numStrokes = 0;
+    nLinePts = 0;
+
+    pStrokes = HeapAlloc(GetProcessHeap(), 0, numStrokes * sizeof(GdiPath*));
+    pStrokes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
+    PATH_InitGdiPath(pStrokes[0]);
+    pStrokes[0]->pFlags = HeapAlloc(GetProcessHeap(), 0, pPath->numEntriesUsed * sizeof(INT));
+    pStrokes[0]->pPoints = HeapAlloc(GetProcessHeap(), 0, pPath->numEntriesUsed * sizeof(POINT));
+    pStrokes[0]->numEntriesUsed = 0;
+
+    for(i = 0, j = 0; i < pPath->numEntriesUsed; i++, j++) {
+        if((i == 0 || (pPath->pFlags[i-1] & PT_CLOSEFIGURE)) &&
+            (pPath->pFlags[i] != PT_MOVETO)) {
+            ERR("Expected PT_MOVETO %s, got path flag %d\n",
+                i == 0 ? "as first point" : "after PT_CLOSEFIGURE",
+                (INT)pPath->pFlags[i]);
+            ret = FALSE;
+            goto end;
+        }
+        switch(pPath->pFlags[i]) {
+            case PT_MOVETO:
+                numStrokes++;
+                j = 0;
+                pStrokes = HeapReAlloc(GetProcessHeap(), 0, pStrokes, numStrokes * sizeof(GdiPath*));
+                pStrokes[numStrokes - 1] = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
+                PATH_InitGdiPath(pStrokes[numStrokes - 1]);
+                pStrokes[numStrokes - 1]->pFlags = HeapAlloc(GetProcessHeap(), 0, pPath->numEntriesUsed * sizeof(INT));
+                pStrokes[numStrokes - 1]->pPoints = HeapAlloc(GetProcessHeap(), 0, pPath->numEntriesUsed * sizeof(POINT));
+                pStrokes[numStrokes - 1]->numEntriesUsed = 0;
+
+                pStrokes[numStrokes - 1]->pFlags[j] = pPath->pFlags[i];
+                pStrokes[numStrokes - 1]->pPoints[j].x = pPath->pPoints[i].x;
+                pStrokes[numStrokes - 1]->pPoints[j].y = pPath->pPoints[i].y;
+                pStrokes[numStrokes - 1]->numEntriesUsed++;
+
+                break;
+            case PT_LINETO:
+            case (PT_LINETO | PT_CLOSEFIGURE):
+                pStrokes[numStrokes - 1]->pFlags[j] = pPath->pFlags[i];
+                pStrokes[numStrokes - 1]->pPoints[j].x = pPath->pPoints[i].x;
+                pStrokes[numStrokes - 1]->pPoints[j].y = pPath->pPoints[i].y;
+                pStrokes[numStrokes - 1]->numEntriesUsed++;
+                break;
+            case PT_BEZIERTO:
+                // should never happen because of the FlattenPath call
+                ERR("Should never happen \n");
+                break;
+            default:
+                ERR("Got path flag %d\n", (INT)pPath->pFlags[i]);
+                ret = FALSE;
+                goto end;
+        }
+    }
+
+    pNewPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
+    PATH_InitGdiPath(pNewPath);
+    pNewPath->pFlags = HeapAlloc(GetProcessHeap(), 0, 4 * pPath->numEntriesUsed * sizeof(INT));
+    pNewPath->pPoints = HeapAlloc(GetProcessHeap(), 0, 4 * pPath->numEntriesUsed * sizeof(POINT));
+    pNewPath->numEntriesUsed = 0;
+    pNewPath->numEntriesAllocated = 4 * pPath->numEntriesUsed;
+
+    for(i = 0; i < numStrokes; i++) {
+        pUpPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
+        PATH_InitGdiPath(pUpPath);
+        pUpPath->pFlags = HeapAlloc(GetProcessHeap(), 0, 2 * pStrokes[i]->numEntriesUsed * sizeof(INT));
+        pUpPath->pPoints = HeapAlloc(GetProcessHeap(), 0, 2 * pStrokes[i]->numEntriesUsed * sizeof(POINT));
+        pUpPath->numEntriesUsed = 0;
+        pDownPath = HeapAlloc(GetProcessHeap(), 0, sizeof(GdiPath));
+        PATH_InitGdiPath(pDownPath);
+        pDownPath->pFlags = HeapAlloc(GetProcessHeap(), 0, 2 * pStrokes[i]->numEntriesUsed * sizeof(INT));
+        pDownPath->pPoints = HeapAlloc(GetProcessHeap(), 0, 2 * pStrokes[i]->numEntriesUsed * sizeof(POINT));
+        pDownPath->numEntriesUsed = 0;
+        for(j = 0; j < pStrokes[i]->numEntriesUsed - 1; j++) {
+            if(pStrokes[i]->pPoints[j+1].x != pStrokes[i]->pPoints[j].x) {
+                nPente = (pStrokes[i]->pPoints[j+1].y - pStrokes[i]->pPoints[j].y) / (pStrokes[i]->pPoints[j+1].x - pStrokes[i]->pPoints[j].x);
+                fCos = cos(atan(nPente));
+                fSin = sin(atan(nPente));
+            }
+            else {
+                fCos = 0;
+                fSin = 1;
+            }
+
+            // FIXME : Improve corners
+            pUpPath->pPoints[2 * j].x = pStrokes[i]->pPoints[j].x + penWidthOut * fSin;
+            pUpPath->pPoints[2 * j].y = pStrokes[i]->pPoints[j].y + penWidthOut * fCos;
+            pUpPath->pFlags[2 * j] = pStrokes[i]->pFlags[j];
+            pUpPath->pPoints[2 * j + 1] .x = pStrokes[i]->pPoints[j+1].x + penWidthOut * fSin;
+            pUpPath->pPoints[2 * j + 1] .y = pStrokes[i]->pPoints[j+1].y + penWidthOut * fCos;
+            pUpPath->pFlags[2 * j + 1] = PT_LINETO;
+            pUpPath->numEntriesUsed = pUpPath->numEntriesUsed + 2;
+
+            pDownPath->pPoints[2 * j].x = pStrokes[i]->pPoints[j].x - penWidthIn * fSin;
+            pDownPath->pPoints[2 * j].y = pStrokes[i]->pPoints[j].y - penWidthIn * fCos;
+            pDownPath->pFlags[2 * j] = PT_LINETO;
+            pDownPath->pPoints[2 * j + 1] .x = pStrokes[i]->pPoints[j+1].x - penWidthIn * fSin;
+            pDownPath->pPoints[2 * j + 1] .y = pStrokes[i]->pPoints[j+1].y - penWidthIn * fCos;
+            pDownPath->pFlags[2 * j + 1] = PT_LINETO;
+            pDownPath->numEntriesUsed = pUpPath->numEntriesUsed;
+        }
+
+        for(j = 0; j < pUpPath->numEntriesUsed; j++) {
+            pNewPath->pPoints[pNewPath->numEntriesUsed + j].x = pUpPath->pPoints[j].x;
+            pNewPath->pPoints[pNewPath->numEntriesUsed + j].y = pUpPath->pPoints[j].y;
+            pNewPath->pFlags[pNewPath->numEntriesUsed + j] = pUpPath->pFlags[j];
+            pNewPath->pPoints[pNewPath->numEntriesUsed + pUpPath->numEntriesUsed + j].x = pDownPath->pPoints[pUpPath->numEntriesUsed - j - 1].x;
+            pNewPath->pPoints[pNewPath->numEntriesUsed + pUpPath->numEntriesUsed + j].y = pDownPath->pPoints[pUpPath->numEntriesUsed - j - 1].y;
+            pNewPath->pFlags[pNewPath->numEntriesUsed + pUpPath->numEntriesUsed + j] = pDownPath->pFlags[pUpPath->numEntriesUsed - j - 1];
+        }
+        pNewPath->numEntriesUsed += 2 * pUpPath->numEntriesUsed;
+        pNewPath->pFlags[pNewPath->numEntriesUsed - 1] = PT_CLOSEFIGURE | PT_LINETO;
+
+        PATH_DestroyGdiPath(pStrokes[i]);
+        HeapFree(GetProcessHeap(), 0, pStrokes[i]);
+        PATH_DestroyGdiPath(pUpPath);
+        HeapFree(GetProcessHeap(), 0, pUpPath);
+        PATH_DestroyGdiPath(pDownPath);
+        HeapFree(GetProcessHeap(), 0, pDownPath);
+    }
+    HeapFree(GetProcessHeap(), 0, pStrokes);
+
+    pNewPath->state = PATH_Closed;
+    if(!PATH_AssignGdiPath(pPath, pNewPath)) {
+        ERR("Assign path failed\n");
+        ret = FALSE;
+        goto end;
+    }
+    PATH_DestroyGdiPath(pNewPath);
+    HeapFree(GetProcessHeap(), 0, pNewPath);
+
+    ret = TRUE;
+
+end :
+    GDI_ReleaseObj( hdc );
+    return ret;
+}
+


More information about the wine-patches mailing list