[PATCH 17/20] gdiplus: Implement GdipAddPathString
Maarten Lankhorst
m.b.lankhorst at gmail.com
Thu Feb 17 04:06:43 CST 2011
---
dlls/gdiplus/gdiplus_private.h | 10 ++
dlls/gdiplus/graphics.c | 7 +--
dlls/gdiplus/graphicspath.c | 181 +++++++++++++++++++++++++++++++++++++++-
3 files changed, 188 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..a7a0249 100644
--- a/dlls/gdiplus/graphicspath.c
+++ b/dlls/gdiplus/graphicspath.c
@@ -831,16 +831,189 @@ 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)
+{
+ struct format_string_args *args = priv;
+ GpPath *path = args->path;
+ GpStatus status = Ok;
+ MAT2 identity = { {0,1}, {0,0}, {0,0}, {0,1} };
+ 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;
+ OUTLINETEXTMETRICW metric = { sizeof(metric) };
+ 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);
+ DeleteObject(SelectObject(dc, hfont));
+ GetOutlineTextMetricsW(dc, sizeof(metric), &metric);
+
+ 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)
--
1.7.2.3
--------------090201020408020506010501--
More information about the wine-patches
mailing list