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..245a59d5f54 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)