From 421c83cd7b15a42617fd942888eca0c81f6d2278 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 13 May 2019 14:21:47 +0300 Subject: [PATCH] dwrite: Improve returned design glyph metrics. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/dwrite_private.h | 71 +++++++++++++++++++++++++++++++----- dlls/dwrite/font.c | 51 ++++---------------------- dlls/dwrite/freetype.c | 25 +++++++------ dlls/dwrite/opentype.c | 21 +++++++++++ 4 files changed, 103 insertions(+), 65 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index e2aa2131a11..32ccd63c3eb 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -164,12 +164,69 @@ struct fontface_desc struct dwrite_font_data *font_data; /* could be NULL when face is created directly with IDWriteFactory::CreateFontFace() */ }; +struct dwrite_fonttable +{ + const BYTE *data; + void *context; + UINT32 size; + BOOL exists; +}; + struct fontfacecached { struct list entry; IDWriteFontFace4 *fontface; }; +#define GLYPH_BLOCK_SHIFT 8 +#define GLYPH_BLOCK_SIZE (1UL << GLYPH_BLOCK_SHIFT) +#define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1) +#define GLYPH_MAX 65536 + +struct dwrite_fontface +{ + IDWriteFontFace4 IDWriteFontFace4_iface; + LONG ref; + + IDWriteFontFileStream *stream; + IDWriteFontFile **files; + UINT32 file_count; + UINT32 index; + + IDWriteFactory5 *factory; + struct fontfacecached *cached; + + USHORT simulations; + DWRITE_FONT_FACE_TYPE type; + DWRITE_FONT_METRICS1 metrics; + DWRITE_CARET_METRICS caret; + struct + { + unsigned int ascent; + unsigned int descent; + } typo_metrics; + INT charmap; + UINT16 flags; + + struct dwrite_fonttable cmap; + struct dwrite_fonttable vdmx; + struct dwrite_fonttable gasp; + struct dwrite_fonttable cpal; + struct dwrite_fonttable colr; + DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE]; + + DWRITE_FONT_STYLE style; + DWRITE_FONT_STRETCH stretch; + DWRITE_FONT_WEIGHT weight; + DWRITE_PANOSE panose; + FONTSIGNATURE fontsig; + UINT32 glyph_image_formats; + + struct scriptshaping_cache *shaping_cache; + + LOGFONTW lf; +}; + extern HRESULT create_numbersubstitution(DWRITE_NUMBER_SUBSTITUTION_METHOD,const WCHAR *locale,BOOL,IDWriteNumberSubstitution**) DECLSPEC_HIDDEN; extern HRESULT create_textformat(const WCHAR*,IDWriteFontCollection*,DWRITE_FONT_WEIGHT,DWRITE_FONT_STYLE,DWRITE_FONT_STRETCH, FLOAT,const WCHAR*,IDWriteTextFormat**) DECLSPEC_HIDDEN; @@ -241,14 +298,6 @@ struct file_stream_desc { UINT32 face_index; }; -struct dwrite_fonttable -{ - const BYTE *data; - void *context; - UINT32 size; - BOOL exists; -}; - extern const void* get_fontface_table(IDWriteFontFace4 *fontface, UINT32 tag, struct dwrite_fonttable *table) DECLSPEC_HIDDEN; @@ -258,6 +307,8 @@ extern HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *t DWRITE_UNICODE_RANGE *ranges, unsigned int *count) DECLSPEC_HIDDEN; extern void opentype_get_font_properties(struct file_stream_desc*,struct dwrite_font_props*) DECLSPEC_HIDDEN; extern void opentype_get_font_metrics(struct file_stream_desc*,DWRITE_FONT_METRICS1*,DWRITE_CARET_METRICS*) DECLSPEC_HIDDEN; +extern void opentype_get_font_typo_metrics(struct file_stream_desc *stream_desc, unsigned int *ascent, + unsigned int *descent) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_info_strings(const void*,DWRITE_INFORMATIONAL_STRING_ID,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_familyname(struct file_stream_desc*,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_facename(struct file_stream_desc*,WCHAR*,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; @@ -317,7 +368,9 @@ struct dwrite_glyphbitmap extern BOOL init_freetype(void) DECLSPEC_HIDDEN; extern void release_freetype(void) DECLSPEC_HIDDEN; -extern HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4*,UINT16,UINT16,DWRITE_GLYPH_METRICS*) 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(IDWriteFontFace4*) DECLSPEC_HIDDEN; extern BOOL freetype_is_monospaced(IDWriteFontFace4*) DECLSPEC_HIDDEN; extern HRESULT freetype_get_glyphrun_outline(IDWriteFontFace4 *fontface, float emsize, UINT16 const *glyphs, diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 732ca371f2d..5a3afefb279 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -207,44 +207,6 @@ enum fontface_flags { FONTFACE_HAS_VERTICAL_VARIANTS = 1 << 3 }; -struct dwrite_fontface { - IDWriteFontFace4 IDWriteFontFace4_iface; - LONG ref; - - IDWriteFontFileStream *stream; - IDWriteFontFile **files; - UINT32 file_count; - UINT32 index; - - IDWriteFactory5 *factory; - struct fontfacecached *cached; - - USHORT simulations; - DWRITE_FONT_FACE_TYPE type; - DWRITE_FONT_METRICS1 metrics; - DWRITE_CARET_METRICS caret; - INT charmap; - UINT16 flags; - - struct dwrite_fonttable cmap; - struct dwrite_fonttable vdmx; - struct dwrite_fonttable gasp; - struct dwrite_fonttable cpal; - struct dwrite_fonttable colr; - DWRITE_GLYPH_METRICS *glyphs[GLYPH_MAX/GLYPH_BLOCK_SIZE]; - - DWRITE_FONT_STYLE style; - DWRITE_FONT_STRETCH stretch; - DWRITE_FONT_WEIGHT weight; - DWRITE_PANOSE panose; - FONTSIGNATURE fontsig; - UINT32 glyph_image_formats; - - struct scriptshaping_cache *shaping_cache; - - LOGFONTW lf; -}; - struct dwrite_fontfile { IDWriteFontFile IDWriteFontFile_iface; LONG ref; @@ -636,11 +598,11 @@ static UINT16 WINAPI dwritefontface_GetGlyphCount(IDWriteFontFace4 *iface) static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *iface, UINT16 const *glyphs, UINT32 glyph_count, DWRITE_GLYPH_METRICS *ret, BOOL is_sideways) { - struct dwrite_fontface *This = impl_from_IDWriteFontFace4(iface); + struct dwrite_fontface *fontface = impl_from_IDWriteFontFace4(iface); + unsigned int i; HRESULT hr; - UINT32 i; - TRACE("(%p)->(%p %u %p %d)\n", This, glyphs, glyph_count, ret, is_sideways); + TRACE("%p, %p, %u, %p, %d.\n", iface, glyphs, glyph_count, ret, is_sideways); if (!glyphs) return E_INVALIDARG; @@ -651,10 +613,10 @@ static HRESULT WINAPI dwritefontface_GetDesignGlyphMetrics(IDWriteFontFace4 *ifa for (i = 0; i < glyph_count; i++) { DWRITE_GLYPH_METRICS metrics; - hr = get_cached_glyph_metrics(This, glyphs[i], &metrics); + hr = get_cached_glyph_metrics(fontface, glyphs[i], &metrics); if (hr != S_OK) { - freetype_get_design_glyph_metrics(iface, This->metrics.designUnitsPerEm, glyphs[i], &metrics); - hr = set_cached_glyph_metrics(This, glyphs[i], &metrics); + freetype_get_design_glyph_metrics(fontface, glyphs[i], &metrics); + hr = set_cached_glyph_metrics(fontface, glyphs[i], &metrics); if (FAILED(hr)) return hr; } @@ -4505,6 +4467,7 @@ HRESULT create_fontface(const struct fontface_desc *desc, struct list *cached_li stream_desc.face_type = desc->face_type; stream_desc.face_index = desc->index; opentype_get_font_metrics(&stream_desc, &fontface->metrics, &fontface->caret); + opentype_get_font_typo_metrics(&stream_desc, &fontface->typo_metrics.ascent, &fontface->typo_metrics.descent); if (desc->simulations & DWRITE_FONT_SIMULATIONS_OBLIQUE) { /* TODO: test what happens if caret is already slanted */ if (fontface->caret.slopeRise == 1) { diff --git a/dlls/dwrite/freetype.c b/dlls/dwrite/freetype.c index fd94829e686..16317036e34 100644 --- a/dlls/dwrite/freetype.c +++ b/dlls/dwrite/freetype.c @@ -263,14 +263,14 @@ void freetype_notify_cacheremove(IDWriteFontFace4 *fontface) LeaveCriticalSection(&freetype_cs); } -HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, DWRITE_GLYPH_METRICS *ret) +HRESULT freetype_get_design_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *ret) { FTC_ScalerRec scaler; FT_Size size; - scaler.face_id = fontface; - scaler.width = unitsperEm; - scaler.height = unitsperEm; + scaler.face_id = &fontface->IDWriteFontFace4_iface; + scaler.width = fontface->metrics.designUnitsPerEm; + scaler.height = fontface->metrics.designUnitsPerEm; scaler.pixel = 1; scaler.x_res = 0; scaler.y_res = 0; @@ -278,22 +278,23 @@ HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4 *fontface, UINT16 uni EnterCriticalSection(&freetype_cs); if (pFTC_Manager_LookupSize(cache_manager, &scaler, &size) == 0) { if (pFT_Load_Glyph(size->face, glyph, FT_LOAD_NO_SCALE) == 0) { - USHORT simulations = IDWriteFontFace4_GetSimulations(fontface); FT_Glyph_Metrics *metrics = &size->face->glyph->metrics; ret->leftSideBearing = metrics->horiBearingX; ret->advanceWidth = metrics->horiAdvance; ret->rightSideBearing = metrics->horiAdvance - metrics->horiBearingX - metrics->width; - ret->topSideBearing = metrics->vertBearingY; + ret->advanceHeight = metrics->vertAdvance; - ret->bottomSideBearing = metrics->vertAdvance - metrics->vertBearingY - metrics->height; - ret->verticalOriginY = metrics->height + metrics->vertBearingY; + ret->verticalOriginY = fontface->typo_metrics.ascent; + ret->topSideBearing = fontface->typo_metrics.ascent - metrics->horiBearingY; + ret->bottomSideBearing = metrics->vertAdvance - metrics->height - ret->topSideBearing; /* Adjust in case of bold simulation, glyphs without contours are ignored. */ - if (simulations & DWRITE_FONT_SIMULATIONS_BOLD && size->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && - size->face->glyph->outline.n_contours != 0) { + if (fontface->simulations & DWRITE_FONT_SIMULATIONS_BOLD && + size->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE && size->face->glyph->outline.n_contours) + { if (ret->advanceWidth) - ret->advanceWidth += (unitsperEm + 49) / 50; + ret->advanceWidth += (fontface->metrics.designUnitsPerEm + 49) / 50; } } } @@ -929,7 +930,7 @@ void freetype_notify_cacheremove(IDWriteFontFace4 *fontface) { } -HRESULT freetype_get_design_glyph_metrics(IDWriteFontFace4 *fontface, UINT16 unitsperEm, UINT16 glyph, DWRITE_GLYPH_METRICS *ret) +HRESULT freetype_get_design_glyph_metrics(struct dwrite_fontface *fontface, UINT16 glyph, DWRITE_GLYPH_METRICS *ret) { return E_NOTIMPL; } diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 4772236770d..e8efa1d1963 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -1553,6 +1553,27 @@ HRESULT opentype_cmap_get_unicode_ranges(const struct dwrite_fonttable *cmap, un return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK; } +void opentype_get_font_typo_metrics(struct file_stream_desc *stream_desc, unsigned int *ascent, unsigned int *descent) +{ + const TT_OS2_V2 *data; + unsigned int size; + void *context; + + opentype_get_font_table(stream_desc, MS_OS2_TAG, (const void **)&data, &context, &size, NULL); + + *ascent = *descent = 0; + + if (size >= FIELD_OFFSET(TT_OS2_V2, sTypoLineGap)) + { + SHORT value = GET_BE_WORD(data->sTypoDescender); + *ascent = GET_BE_WORD(data->sTypoAscender); + *descent = value < 0 ? -value : 0; + } + + if (data) + IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, context); +} + void opentype_get_font_metrics(struct file_stream_desc *stream_desc, DWRITE_FONT_METRICS1 *metrics, DWRITE_CARET_METRICS *caret) { void *os2_context, *head_context, *post_context, *hhea_context;