[PATCH] dwrite: Return complete outline data from freetype integration code.

Nikolay Sivov nsivov at codeweavers.com
Mon Mar 22 02:59:16 CDT 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---

It makes it possible to cache outlines in directwrite format, that always differs
at least because of Y axis direction transformation. At the same time user callbacks
are not longer called from freetype integration code, which is important for splitting
the library.

 dlls/dwrite/dwrite_private.h |  33 +++++++++-
 dlls/dwrite/font.c           |  71 +++++++++++++++++++-
 dlls/dwrite/freetype.c       | 123 +++++++++++++++++++----------------
 3 files changed, 168 insertions(+), 59 deletions(-)

diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h
index fe1a16c8899..47be661555c 100644
--- a/dlls/dwrite/dwrite_private.h
+++ b/dlls/dwrite/dwrite_private.h
@@ -457,14 +457,43 @@ struct dwrite_glyphbitmap
     DWRITE_MATRIX *m;
 };
 
+enum dwrite_outline_tags
+{
+    OUTLINE_BEGIN_FIGURE,
+    OUTLINE_END_FIGURE,
+    OUTLINE_LINE,
+    OUTLINE_BEZIER,
+};
+
+struct dwrite_outline
+{
+    struct
+    {
+        unsigned char *values;
+        size_t count;
+        size_t size;
+    } tags;
+
+    struct
+    {
+        D2D1_POINT_2F *values;
+        size_t count;
+        size_t size;
+    } points;
+};
+
+extern int dwrite_outline_push_tag(struct dwrite_outline *outline, unsigned char tag) DECLSPEC_HIDDEN;
+extern int dwrite_outline_push_points(struct dwrite_outline *outline, const D2D1_POINT_2F *points,
+        unsigned int count) DECLSPEC_HIDDEN;
+
 extern BOOL init_freetype(void) DECLSPEC_HIDDEN;
 extern void release_freetype(void) DECLSPEC_HIDDEN;
 
 extern HRESULT freetype_get_design_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph,
         DWRITE_GLYPH_METRICS *metrics) DECLSPEC_HIDDEN;
 extern void freetype_notify_cacheremove(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
-extern HRESULT freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
-        D2D1_POINT_2F origin, IDWriteGeometrySink *sink) DECLSPEC_HIDDEN;
+extern int freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
+        struct dwrite_outline *outline) DECLSPEC_HIDDEN;
 extern UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface) DECLSPEC_HIDDEN;
 extern void freetype_get_glyph_bbox(struct dwrite_glyphbitmap *bitmap_desc) DECLSPEC_HIDDEN;
 extern BOOL freetype_get_glyph_bitmap(struct dwrite_glyphbitmap*) DECLSPEC_HIDDEN;
diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c
index 0167878e912..4c62f2a0e37 100644
--- a/dlls/dwrite/font.c
+++ b/dlls/dwrite/font.c
@@ -823,13 +823,50 @@ static void WINAPI dwritefontface_ReleaseFontTable(IDWriteFontFace5 *iface, void
     IDWriteFontFileStream_ReleaseFileFragment(fontface->stream, table_context);
 }
 
+int dwrite_outline_push_tag(struct dwrite_outline *outline, unsigned char tag)
+{
+    if (!dwrite_array_reserve((void **)&outline->tags.values, &outline->tags.size, outline->tags.count + 1,
+            sizeof(*outline->tags.values)))
+    {
+        return 1;
+    }
+
+    outline->tags.values[outline->tags.count++] = tag;
+
+    return 0;
+}
+
+int dwrite_outline_push_points(struct dwrite_outline *outline, const D2D1_POINT_2F *points, unsigned int count)
+{
+    if (!dwrite_array_reserve((void **)&outline->points.values, &outline->points.size, outline->points.count + count,
+            sizeof(*outline->points.values)))
+    {
+        return 1;
+    }
+
+    memcpy(&outline->points.values[outline->points.count], points, sizeof(*points) * count);
+    outline->points.count += count;
+
+    return 0;
+}
+
+static void apply_outline_point_offset(const D2D1_POINT_2F *src, const D2D1_POINT_2F *offset,
+        D2D1_POINT_2F *dst)
+{
+    dst->x = src->x + offset->x;
+    dst->y = src->y + offset->y;
+}
+
 static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface, FLOAT emSize,
     UINT16 const *glyphs, FLOAT const* advances, DWRITE_GLYPH_OFFSET const *offsets,
     UINT32 count, BOOL is_sideways, BOOL is_rtl, IDWriteGeometrySink *sink)
 {
     D2D1_POINT_2F *origins, baseline_origin = { 0 };
+    struct dwrite_outline outline = { 0 };
+    D2D1_BEZIER_SEGMENT segment;
+    D2D1_POINT_2F point;
     DWRITE_GLYPH_RUN run;
-    unsigned int i;
+    unsigned int i, j, p;
     HRESULT hr;
 
     TRACE("%p, %.8e, %p, %p, %p, %u, %d, %d, %p.\n", iface, emSize, glyphs, advances, offsets,
@@ -863,10 +900,40 @@ static HRESULT WINAPI dwritefontface_GetGlyphRunOutline(IDWriteFontFace5 *iface,
 
     for (i = 0; i < count; ++i)
     {
-        if (FAILED(hr = freetype_get_glyph_outline(iface, emSize, glyphs[i], origins[i], sink)))
+        outline.tags.count = outline.points.count = 0;
+        if (freetype_get_glyph_outline(iface, emSize, glyphs[i], &outline))
+        {
             WARN("Failed to get glyph outline for glyph %u.\n", glyphs[i]);
+            continue;
+        }
+
+        for (j = 0, p = 0; j < outline.tags.count; ++j)
+        {
+            switch (outline.tags.values[j])
+            {
+                case OUTLINE_BEGIN_FIGURE:
+                    apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
+                    ID2D1SimplifiedGeometrySink_BeginFigure(sink, point, D2D1_FIGURE_BEGIN_FILLED);
+                    break;
+                case OUTLINE_END_FIGURE:
+                    ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
+                    break;
+                case OUTLINE_LINE:
+                    apply_outline_point_offset(&outline.points.values[p++], &origins[i], &point);
+                    ID2D1SimplifiedGeometrySink_AddLines(sink, &point, 1);
+                    break;
+                case OUTLINE_BEZIER:
+                    apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point1);
+                    apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point2);
+                    apply_outline_point_offset(&outline.points.values[p++], &origins[i], &segment.point3);
+                    ID2D1SimplifiedGeometrySink_AddBeziers(sink, &segment, 1);
+                    break;
+            }
+        }
     }
 
+    heap_free(outline.tags.values);
+    heap_free(outline.points.values);
     heap_free(origins);
 
     return S_OK;
diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c
index 83b2ae1bc88..9e4001d11c2 100644
--- a/dlls/dwrite/freetype.c
+++ b/dlls/dwrite/freetype.c
@@ -296,40 +296,46 @@ HRESULT freetype_get_design_glyph_metrics(struct dwrite_fontface *fontface, UINT
     return S_OK;
 }
 
-struct decompose_context {
-    IDWriteGeometrySink *sink;
-    D2D1_POINT_2F offset;
+struct decompose_context
+{
+    struct dwrite_outline *outline;
     BOOL figure_started;
     BOOL move_to;     /* last call was 'move_to' */
     FT_Vector origin; /* 'pen' position from last call */
 };
 
-static inline void ft_vector_to_d2d_point(const FT_Vector *v, D2D1_POINT_2F offset, D2D1_POINT_2F *p)
+static inline void ft_vector_to_d2d_point(const FT_Vector *v, D2D1_POINT_2F *p)
 {
-    p->x = (v->x / 64.0f) + offset.x;
-    p->y = (v->y / 64.0f) + offset.y;
+    p->x = v->x / 64.0f;
+    p->y = v->y / 64.0f;
 }
 
-static void decompose_beginfigure(struct decompose_context *ctxt)
+static int decompose_beginfigure(struct decompose_context *ctxt)
 {
     D2D1_POINT_2F point;
+    int ret;
 
     if (!ctxt->move_to)
-        return;
+        return 0;
 
-    ft_vector_to_d2d_point(&ctxt->origin, ctxt->offset, &point);
-    ID2D1SimplifiedGeometrySink_BeginFigure(ctxt->sink, point, D2D1_FIGURE_BEGIN_FILLED);
+    ft_vector_to_d2d_point(&ctxt->origin, &point);
+    if ((ret = dwrite_outline_push_tag(ctxt->outline, OUTLINE_BEGIN_FIGURE))) return ret;
+    if ((ret = dwrite_outline_push_points(ctxt->outline, &point, 1))) return ret;
 
     ctxt->figure_started = TRUE;
     ctxt->move_to = FALSE;
+
+    return 0;
 }
 
 static int decompose_move_to(const FT_Vector *to, void *user)
 {
-    struct decompose_context *ctxt = (struct decompose_context*)user;
+    struct decompose_context *ctxt = (struct decompose_context *)user;
+    int ret;
 
-    if (ctxt->figure_started) {
-        ID2D1SimplifiedGeometrySink_EndFigure(ctxt->sink, D2D1_FIGURE_END_CLOSED);
+    if (ctxt->figure_started)
+    {
+        if ((ret = dwrite_outline_push_tag(ctxt->outline, OUTLINE_END_FIGURE))) return ret;
         ctxt->figure_started = FALSE;
     }
 
@@ -340,17 +346,19 @@ static int decompose_move_to(const FT_Vector *to, void *user)
 
 static int decompose_line_to(const FT_Vector *to, void *user)
 {
-    struct decompose_context *ctxt = (struct decompose_context*)user;
+    struct decompose_context *ctxt = (struct decompose_context *)user;
     D2D1_POINT_2F point;
+    int ret;
 
     /* Special case for empty contours, in a way freetype returns them. */
     if (ctxt->move_to && !memcmp(to, &ctxt->origin, sizeof(*to)))
         return 0;
 
-    decompose_beginfigure(ctxt);
+    ft_vector_to_d2d_point(to, &point);
 
-    ft_vector_to_d2d_point(to, ctxt->offset, &point);
-    ID2D1SimplifiedGeometrySink_AddLines(ctxt->sink, &point, 1);
+    if ((ret = decompose_beginfigure(ctxt))) return ret;
+    if ((ret = dwrite_outline_push_points(ctxt->outline, &point, 1))) return ret;
+    if ((ret = dwrite_outline_push_tag(ctxt->outline, OUTLINE_LINE))) return ret;
 
     ctxt->origin = *to;
     return 0;
@@ -358,11 +366,13 @@ static int decompose_line_to(const FT_Vector *to, void *user)
 
 static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, void *user)
 {
-    struct decompose_context *ctxt = (struct decompose_context*)user;
+    struct decompose_context *ctxt = (struct decompose_context *)user;
     D2D1_POINT_2F points[3];
     FT_Vector cubic[3];
+    int ret;
 
-    decompose_beginfigure(ctxt);
+    if ((ret = decompose_beginfigure(ctxt)))
+        return ret;
 
     /* convert from quadratic to cubic */
 
@@ -394,10 +404,11 @@ static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, voi
     cubic[1].y += (to->y + 1) / 3;
     cubic[2] = *to;
 
-    ft_vector_to_d2d_point(cubic, ctxt->offset, points);
-    ft_vector_to_d2d_point(cubic + 1, ctxt->offset, points + 1);
-    ft_vector_to_d2d_point(cubic + 2, ctxt->offset, points + 2);
-    ID2D1SimplifiedGeometrySink_AddBeziers(ctxt->sink, (D2D1_BEZIER_SEGMENT*)points, 1);
+    ft_vector_to_d2d_point(cubic, points);
+    ft_vector_to_d2d_point(cubic + 1, points + 1);
+    ft_vector_to_d2d_point(cubic + 2, points + 2);
+    if ((ret = dwrite_outline_push_points(ctxt->outline, points, 3))) return ret;
+    if ((ret = dwrite_outline_push_tag(ctxt->outline, OUTLINE_BEZIER))) return ret;
     ctxt->origin = *to;
     return 0;
 }
@@ -405,22 +416,28 @@ static int decompose_conic_to(const FT_Vector *control, const FT_Vector *to, voi
 static int decompose_cubic_to(const FT_Vector *control1, const FT_Vector *control2,
     const FT_Vector *to, void *user)
 {
-    struct decompose_context *ctxt = (struct decompose_context*)user;
+    struct decompose_context *ctxt = (struct decompose_context *)user;
     D2D1_POINT_2F points[3];
+    int ret;
 
-    decompose_beginfigure(ctxt);
+    if ((ret = decompose_beginfigure(ctxt)))
+        return ret;
 
-    ft_vector_to_d2d_point(control1, ctxt->offset, points);
-    ft_vector_to_d2d_point(control2, ctxt->offset, points + 1);
-    ft_vector_to_d2d_point(to, ctxt->offset, points + 2);
-    ID2D1SimplifiedGeometrySink_AddBeziers(ctxt->sink, (D2D1_BEZIER_SEGMENT*)points, 1);
+    ft_vector_to_d2d_point(control1, points);
+    ft_vector_to_d2d_point(control2, points + 1);
+    ft_vector_to_d2d_point(to, points + 2);
     ctxt->origin = *to;
+
+    if ((ret = dwrite_outline_push_points(ctxt->outline, points, 3))) return ret;
+    if ((ret = dwrite_outline_push_tag(ctxt->outline, OUTLINE_BEZIER))) return ret;
+
     return 0;
 }
 
-static void decompose_outline(FT_Outline *outline, D2D1_POINT_2F offset, IDWriteGeometrySink *sink)
+static int decompose_outline(FT_Outline *ft_outline, struct dwrite_outline *outline)
 {
-    static const FT_Outline_Funcs decompose_funcs = {
+    static const FT_Outline_Funcs decompose_funcs =
+    {
         decompose_move_to,
         decompose_line_to,
         decompose_conic_to,
@@ -428,19 +445,17 @@ static void decompose_outline(FT_Outline *outline, D2D1_POINT_2F offset, IDWrite
         0,
         0
     };
-    struct decompose_context context;
+    struct decompose_context context = { 0 };
+    int ret;
 
-    context.sink = sink;
-    context.offset = offset;
-    context.figure_started = FALSE;
-    context.move_to = FALSE;
-    context.origin.x = 0;
-    context.origin.y = 0;
+    context.outline = outline;
 
-    pFT_Outline_Decompose(outline, &decompose_funcs, &context);
+    ret = pFT_Outline_Decompose(ft_outline, &decompose_funcs, &context);
 
-    if (context.figure_started)
-        ID2D1SimplifiedGeometrySink_EndFigure(sink, D2D1_FIGURE_END_CLOSED);
+    if (!ret && context.figure_started)
+        ret = dwrite_outline_push_tag(outline, OUTLINE_END_FIGURE);
+
+    return ret;
 }
 
 static void embolden_glyph_outline(FT_Outline *outline, FLOAT emsize)
@@ -464,13 +479,13 @@ static void embolden_glyph(FT_Glyph glyph, FLOAT emsize)
     embolden_glyph_outline(&outline_glyph->outline, emsize);
 }
 
-HRESULT freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
-        D2D1_POINT_2F origin, IDWriteGeometrySink *sink)
+int freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
+        struct dwrite_outline *outline)
 {
     FTC_ScalerRec scaler;
     USHORT simulations;
-    HRESULT hr = S_OK;
     FT_Size size;
+    int ret;
 
     simulations = IDWriteFontFace5_GetSimulations(fontface);
 
@@ -482,31 +497,29 @@ HRESULT freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UIN
     scaler.y_res = 0;
 
     EnterCriticalSection(&freetype_cs);
-    if (pFTC_Manager_LookupSize(cache_manager, &scaler, &size) == 0)
+    if (!(ret = pFTC_Manager_LookupSize(cache_manager, &scaler, &size)))
     {
         if (pFT_Load_Glyph(size->face, glyph, FT_LOAD_NO_BITMAP) == 0)
         {
-            FT_Outline *outline = &size->face->glyph->outline;
+            FT_Outline *ft_outline = &size->face->glyph->outline;
             FT_Matrix m;
 
             if (simulations & DWRITE_FONT_SIMULATIONS_BOLD)
-                embolden_glyph_outline(outline, emSize);
+                embolden_glyph_outline(ft_outline, emSize);
 
             m.xx = 1 << 16;
             m.xy = simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE ? (1 << 16) / 3 : 0;
             m.yx = 0;
             m.yy = -(1 << 16); /* flip Y axis */
 
-            pFT_Outline_Transform(outline, &m);
+            pFT_Outline_Transform(ft_outline, &m);
 
-            decompose_outline(outline, origin, sink);
+            ret = decompose_outline(ft_outline, outline);
         }
     }
-    else
-        hr = E_FAIL;
     LeaveCriticalSection(&freetype_cs);
 
-    return hr;
+    return ret;
 }
 
 UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
@@ -797,10 +810,10 @@ HRESULT freetype_get_design_glyph_metrics(struct dwrite_fontface *fontface, UINT
     return E_NOTIMPL;
 }
 
-HRESULT freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
-        D2D1_POINT_2F origin, IDWriteGeometrySink *sink)
+int freetype_get_glyph_outline(IDWriteFontFace5 *fontface, float emSize, UINT16 glyph,
+        struct dwrite_outline *outline)
 {
-    return E_NOTIMPL;
+    return 1;
 }
 
 UINT16 freetype_get_glyphcount(IDWriteFontFace5 *fontface)
-- 
2.30.2




More information about the wine-devel mailing list