Signed-off-by: Nikolay Sivov <nsivov(a)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