dwrite: Return complete outline data from freetype integration code.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-03-22 10:59:16 +03:00 committed by Alexandre Julliard
parent ca143521ed
commit ae3422c615
3 changed files with 168 additions and 59 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)