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:
parent
ca143521ed
commit
ae3422c615
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue