Maarten Lankhorst : gdiplus: Implement GdipAddPathString.

Alexandre Julliard julliard at winehq.org
Thu Mar 3 11:46:23 CST 2011


Module: wine
Branch: master
Commit: b8a1e6c68791ca6e8d583cd2f99d36da498a2ac4
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=b8a1e6c68791ca6e8d583cd2f99d36da498a2ac4

Author: Maarten Lankhorst <m.b.lankhorst at gmail.com>
Date:   Thu Feb 17 11:06:43 2011 +0100

gdiplus: Implement GdipAddPathString.

---

 dlls/gdiplus/gdiplus_private.h |   10 ++
 dlls/gdiplus/graphics.c        |    7 +--
 dlls/gdiplus/graphicspath.c    |  179 +++++++++++++++++++++++++++++++++++++++-
 3 files changed, 186 insertions(+), 10 deletions(-)

diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index 42e28fa..68998df 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -397,4 +397,14 @@ struct GpRegion{
     region_element node;
 };
 
+typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
+    GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    INT lineno, const RectF *bounds, void *user_data);
+
+GpStatus gdip_format_string(HDC hdc,
+    GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    gdip_format_string_callback callback, void *user_data);
+
 #endif
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c
index 5f226e9..43513c8 100644
--- a/dlls/gdiplus/graphics.c
+++ b/dlls/gdiplus/graphics.c
@@ -3989,12 +3989,7 @@ GpStatus WINGDIPAPI GdipIsVisibleRectI(GpGraphics *graphics, INT x, INT y, INT w
     return GdipIsVisibleRect(graphics, (REAL)x, (REAL)y, (REAL)width, (REAL)height, result);
 }
 
-typedef GpStatus (*gdip_format_string_callback)(HDC hdc,
-    GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
-    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
-    INT lineno, const RectF *bounds, void *user_data);
-
-static GpStatus gdip_format_string(HDC hdc,
+GpStatus gdip_format_string(HDC hdc,
     GDIPCONST WCHAR *string, INT length, GDIPCONST GpFont *font,
     GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
     gdip_format_string_callback callback, void *user_data)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c
index 5a68147..992bd7c 100644
--- a/dlls/gdiplus/graphicspath.c
+++ b/dlls/gdiplus/graphicspath.c
@@ -831,16 +831,187 @@ GpStatus WINGDIPAPI GdipAddPathPolygonI(GpPath *path, GDIPCONST GpPoint *points,
     return status;
 }
 
+static float fromfixedpoint(const FIXED v)
+{
+    float f = ((float)v.fract) / (1<<(sizeof(v.fract)*8));
+    f += v.value;
+    return f;
+}
+
+struct format_string_args
+{
+    GpPath *path;
+    UINT maxY;
+};
+
+static GpStatus format_string_callback(HDC dc,
+    GDIPCONST WCHAR *string, INT index, INT length, GDIPCONST GpFont *font,
+    GDIPCONST RectF *rect, GDIPCONST GpStringFormat *format,
+    INT lineno, const RectF *bounds, void *priv)
+{
+    static const MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
+    struct format_string_args *args = priv;
+    GpPath *path = args->path;
+    GpStatus status = Ok;
+    float x = bounds->X;
+    float y = bounds->Y;
+    int i;
+
+    for (i = index; i < length; ++i)
+    {
+        GLYPHMETRICS gm;
+        TTPOLYGONHEADER *ph = NULL;
+        char *start;
+        DWORD len, ofs = 0;
+        UINT bb_end;
+        len = GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, 0, NULL, &identity);
+        if (len == GDI_ERROR)
+        {
+            status = GenericError;
+            break;
+        }
+        ph = GdipAlloc(len);
+        start = (char *)ph;
+        if (!ph || !lengthen_path(path, len / sizeof(POINTFX)))
+        {
+            status = OutOfMemory;
+            break;
+        }
+        GetGlyphOutlineW(dc, string[i], GGO_BEZIER, &gm, len, start, &identity);
+        bb_end = gm.gmBlackBoxY + gm.gmptGlyphOrigin.y;
+        if (bb_end + y > args->maxY)
+            args->maxY = bb_end + y;
+
+        ofs = 0;
+        while (ofs < len)
+        {
+            DWORD ofs_start = ofs;
+            ph = (TTPOLYGONHEADER*)&start[ofs];
+            path->pathdata.Types[path->pathdata.Count] = PathPointTypeStart;
+            path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(ph->pfxStart.x);
+            path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(ph->pfxStart.y);
+            TRACE("Starting at count %i with pos %f, %f)\n", path->pathdata.Count, x, y);
+            ofs += sizeof(*ph);
+            while (ofs - ofs_start < ph->cb)
+            {
+                TTPOLYCURVE *curve = (TTPOLYCURVE*)&start[ofs];
+                int j;
+                ofs += sizeof(TTPOLYCURVE) + (curve->cpfx - 1) * sizeof(POINTFX);
+
+                switch (curve->wType)
+                {
+                case TT_PRIM_LINE:
+                    for (j = 0; j < curve->cpfx; ++j)
+                    {
+                        path->pathdata.Types[path->pathdata.Count] = PathPointTypeLine;
+                        path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x);
+                        path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(curve->apfx[j].y);
+                    }
+                    break;
+                case TT_PRIM_CSPLINE:
+                    for (j = 0; j < curve->cpfx; ++j)
+                    {
+                        path->pathdata.Types[path->pathdata.Count] = PathPointTypeBezier;
+                        path->pathdata.Points[path->pathdata.Count].X = x + fromfixedpoint(curve->apfx[j].x);
+                        path->pathdata.Points[path->pathdata.Count++].Y = y + bb_end - fromfixedpoint(curve->apfx[j].y);
+                    }
+                    break;
+                default:
+                    ERR("Unhandled type: %u\n", curve->wType);
+                    status = GenericError;
+                }
+            }
+            path->pathdata.Types[path->pathdata.Count - 1] |= PathPointTypeCloseSubpath;
+        }
+        path->newfigure = TRUE;
+        x += gm.gmCellIncX;
+        y += gm.gmCellIncY;
+
+        GdipFree(ph);
+        if (status != Ok)
+            break;
+    }
+
+    return status;
+}
+
 GpStatus WINGDIPAPI GdipAddPathString(GpPath* path, GDIPCONST WCHAR* string, INT length, GDIPCONST GpFontFamily* family, INT style, REAL emSize, GDIPCONST RectF* layoutRect, GDIPCONST GpStringFormat* format)
 {
-    FIXME("(%p, %p, %d, %p, %d, %f, %p, %p): stub\n", path, string, length, family, style, emSize, layoutRect, format);
-    return NotImplemented;
+    GpFont *font;
+    GpStatus status;
+    HANDLE hfont;
+    HDC dc;
+    GpPath *backup;
+    struct format_string_args args;
+    int i;
+
+    FIXME("(%p, %s, %d, %p, %d, %f, %p, %p): stub\n", path, debugstr_w(string), length, family, style, emSize, layoutRect, format);
+    if (!path || !string || !family || !emSize || !layoutRect || !format)
+        return InvalidParameter;
+
+    status = GdipCreateFont(family, emSize, style, UnitPixel, &font);
+    if (status != Ok)
+        return status;
+
+    hfont = CreateFontIndirectW(&font->lfw);
+    if (!hfont)
+    {
+        WARN("Failed to create font\n");
+        return GenericError;
+    }
+
+    if ((status = GdipClonePath(path, &backup)) != Ok)
+    {
+        DeleteObject(hfont);
+        return status;
+    }
+
+    dc = CreateCompatibleDC(0);
+    SelectObject(dc, hfont);
+
+    args.path = path;
+    args.maxY = 0;
+    status = gdip_format_string(dc, string, length, NULL, layoutRect, format, format_string_callback, &args);
+
+    DeleteDC(dc);
+    DeleteObject(hfont);
+
+    if (status != Ok) /* free backup */
+    {
+        GdipFree(path->pathdata.Points);
+        GdipFree(path->pathdata.Types);
+        *path = *backup;
+        GdipFree(backup);
+        return status;
+    }
+    if (format && format->vertalign == StringAlignmentCenter && layoutRect->Y + args.maxY < layoutRect->Height)
+    {
+        float inc = layoutRect->Height - args.maxY - layoutRect->Y;
+        inc /= 2;
+        for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
+            path->pathdata.Points[i].Y += inc;
+    } else if (format && format->vertalign == StringAlignmentFar) {
+        float inc = layoutRect->Height - args.maxY - layoutRect->Y;
+        for (i = backup->pathdata.Count; i < path->pathdata.Count; ++i)
+            path->pathdata.Points[i].Y += inc;
+    }
+    GdipDeletePath(backup);
+    return status;
 }
 
 GpStatus WINGDIPAPI GdipAddPathStringI(GpPath* path, GDIPCONST WCHAR* string, INT length, GDIPCONST GpFontFamily* family, INT style, REAL emSize, GDIPCONST Rect* layoutRect, GDIPCONST GpStringFormat* format)
 {
-    FIXME("(%p, %p, %d, %p, %d, %f, %p, %p): stub\n", path, string, length, family, style, emSize, layoutRect, format);
-    return NotImplemented;
+    if (layoutRect)
+    {
+        RectF layoutRectF = {
+            (REAL)layoutRect->X,
+            (REAL)layoutRect->Y,
+            (REAL)layoutRect->Width,
+            (REAL)layoutRect->Height
+        };
+        return GdipAddPathString(path, string, length, family, style, emSize, &layoutRectF, format);
+    }
+    return InvalidParameter;
 }
 
 GpStatus WINGDIPAPI GdipClonePath(GpPath* path, GpPath **clone)




More information about the wine-cvs mailing list