From: Nikolay Sivov Subject: [PATCH 2/2] dwrite: Fix lineGap metric using 'hhea' table values Message-Id: <54784ADE.3060103@codeweavers.com> Date: Fri, 28 Nov 2014 13:13:50 +0300 --- From a028f152f1d1c08f89a0addc1aab7002aefd19ea Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 28 Nov 2014 09:23:51 +0300 Subject: [PATCH 2/2] dwrite: Fix lineGap metric using 'hhea' table values --- dlls/dwrite/dwrite_private.h | 2 +- dlls/dwrite/font.c | 19 ++++--------- dlls/dwrite/opentype.c | 67 +++++++++++++++++++++++++++++++++++++------- dlls/dwrite/tests/font.c | 4 --- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index c600f3e..15379da 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -116,7 +116,7 @@ extern HRESULT opentype_get_font_table(IDWriteFontFileStream*,DWRITE_FONT_FACE_T extern void opentype_cmap_get_glyphindex(void*,UINT32,UINT16*) DECLSPEC_HIDDEN; extern HRESULT opentype_cmap_get_unicode_ranges(void*,UINT32,DWRITE_UNICODE_RANGE*,UINT32*) DECLSPEC_HIDDEN; extern void opentype_get_font_properties(const void*,const void*,DWRITE_FONT_STRETCH*,DWRITE_FONT_WEIGHT*,DWRITE_FONT_STYLE*) DECLSPEC_HIDDEN; -extern void opentype_get_font_metrics(const void*,const void*,const void*,DWRITE_FONT_METRICS1*) DECLSPEC_HIDDEN; +extern void opentype_get_font_metrics(IDWriteFontFileStream*,DWRITE_FONT_FACE_TYPE,UINT32,DWRITE_FONT_METRICS1*) DECLSPEC_HIDDEN; extern HRESULT opentype_get_font_strings_from_id(const void*,DWRITE_INFORMATIONAL_STRING_ID,IDWriteLocalizedStrings**) DECLSPEC_HIDDEN; /* BiDi helpers */ diff --git a/dlls/dwrite/font.c b/dlls/dwrite/font.c index 073f11a..9d11e94 100644 --- a/dlls/dwrite/font.c +++ b/dlls/dwrite/font.c @@ -28,7 +28,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); #define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d') #define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2') -#define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t') #define MS_CMAP_TAG DWRITE_MAKE_OPENTYPE_TAG('c','m','a','p') #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e') @@ -584,29 +583,26 @@ static void get_font_properties_from_stream(IDWriteFontFileStream *stream, DWRIT UINT32 face_index, DWRITE_FONT_METRICS1 *metrics, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) { - const void *tt_os2 = NULL, *tt_head = NULL, *tt_post = NULL; - void *os2_context, *head_context, *post_context; + const void *tt_os2 = NULL, *tt_head = NULL; + void *os2_context, *head_context; DWRITE_FONT_STRETCH fontstretch; DWRITE_FONT_WEIGHT fontweight; DWRITE_FONT_STYLE fontstyle; opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, &tt_os2, &os2_context, NULL, NULL); opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, &tt_head, &head_context, NULL, NULL); - opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, &tt_post, &post_context, NULL, NULL); if (!stretch) stretch = &fontstretch; if (!weight) weight = &fontweight; if (!style) style = &fontstyle; opentype_get_font_properties(tt_os2, tt_head, stretch, weight, style); - opentype_get_font_metrics(tt_os2, tt_head, tt_post, metrics); + opentype_get_font_metrics(stream, face_type, face_index, metrics); if (tt_os2) IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context); if (tt_head) IDWriteFontFileStream_ReleaseFileFragment(stream, head_context); - if (tt_post) - IDWriteFontFileStream_ReleaseFileFragment(stream, post_context); } HRESULT convert_fontface_to_logfont(IDWriteFontFace *face, LOGFONTW *logfont) @@ -1458,8 +1454,8 @@ static HRESULT get_filestream_from_file(IDWriteFontFile *file, IDWriteFontFileSt static HRESULT init_font_data(IDWriteFactory *factory, IDWriteFontFile *file, UINT32 face_index, DWRITE_FONT_FACE_TYPE face_type, struct dwrite_font_data *data) { - void *os2_context, *head_context, *post_context; - const void *tt_os2 = NULL, *tt_head = NULL, *tt_post = NULL; + void *os2_context, *head_context; + const void *tt_os2 = NULL, *tt_head = NULL; IDWriteFontFileStream *stream; HRESULT hr; @@ -1476,17 +1472,14 @@ static HRESULT init_font_data(IDWriteFactory *factory, IDWriteFontFile *file, UI opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, &tt_os2, &os2_context, NULL, NULL); opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, &tt_head, &head_context, NULL, NULL); - opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, &tt_post, &post_context, NULL, NULL); opentype_get_font_properties(tt_os2, tt_head, &data->stretch, &data->weight, &data->style); - opentype_get_font_metrics(tt_os2, tt_head, tt_post, &data->metrics); + opentype_get_font_metrics(stream, face_type, face_index, &data->metrics); if (tt_os2) IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context); if (tt_head) IDWriteFontFileStream_ReleaseFileFragment(stream, head_context); - if (tt_post) - IDWriteFontFileStream_ReleaseFileFragment(stream, post_context); IDWriteFontFileStream_Release(stream); return S_OK; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 28923c5..a76dd4b 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -24,8 +24,12 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); -#define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f') +#define MS_HEAD_TAG DWRITE_MAKE_OPENTYPE_TAG('h','e','a','d') +#define MS_HHEA_TAG DWRITE_MAKE_OPENTYPE_TAG('h','h','e','a') #define MS_OTTO_TAG DWRITE_MAKE_OPENTYPE_TAG('O','T','T','O') +#define MS_OS2_TAG DWRITE_MAKE_OPENTYPE_TAG('O','S','/','2') +#define MS_POST_TAG DWRITE_MAKE_OPENTYPE_TAG('p','o','s','t') +#define MS_TTCF_TAG DWRITE_MAKE_OPENTYPE_TAG('t','t','c','f') #ifdef WORDS_BIGENDIAN #define GET_BE_WORD(x) (x) @@ -183,6 +187,24 @@ typedef struct USHORT usBreakChar; USHORT usMaxContext; } TT_OS2_V2; + +typedef struct { + ULONG version; + SHORT ascender; + SHORT descender; + SHORT linegap; + USHORT advanceWidthMax; + SHORT minLeftSideBearing; + SHORT minRightSideBearing; + SHORT xMaxExtent; + SHORT caretSlopeRise; + SHORT caretSlopeRun; + SHORT caretOffset; + SHORT reserved[4]; + SHORT metricDataFormat; + USHORT numberOfHMetrics; +} TT_HHEA; + #include "poppack.h" enum OS2_FSSELECTION { @@ -871,14 +893,22 @@ HRESULT opentype_cmap_get_unicode_ranges(void *data, UINT32 max_count, DWRITE_UN return *count > max_count ? E_NOT_SUFFICIENT_BUFFER : S_OK; } -void opentype_get_font_metrics(const void *os2, const void *head, const void *post, DWRITE_FONT_METRICS1 *metrics) +void opentype_get_font_metrics(IDWriteFontFileStream *stream, DWRITE_FONT_FACE_TYPE face_type, UINT32 face_index, + DWRITE_FONT_METRICS1 *metrics) { - TT_OS2_V2 *tt_os2 = (TT_OS2_V2*)os2; - TT_HEAD *tt_head = (TT_HEAD*)head; - TT_POST *tt_post = (TT_POST*)post; + void *os2_context, *head_context, *post_context, *hhea_context; + const TT_OS2_V2 *tt_os2; + const TT_HEAD *tt_head; + const TT_POST *tt_post; + const TT_HHEA *tt_hhea; memset(metrics, 0, sizeof(*metrics)); + opentype_get_font_table(stream, face_type, face_index, MS_OS2_TAG, (const void**)&tt_os2, &os2_context, NULL, NULL); + opentype_get_font_table(stream, face_type, face_index, MS_HEAD_TAG, (const void**)&tt_head, &head_context, NULL, NULL); + opentype_get_font_table(stream, face_type, face_index, MS_POST_TAG, (const void**)&tt_post, &post_context, NULL, NULL); + opentype_get_font_table(stream, face_type, face_index, MS_HHEA_TAG, (const void**)&tt_hhea, &hhea_context, NULL, NULL); + if (tt_head) { metrics->designUnitsPerEm = GET_BE_WORD(tt_head->unitsPerEm); metrics->glyphBoxLeft = GET_BE_WORD(tt_head->xMin); @@ -890,11 +920,19 @@ void opentype_get_font_metrics(const void *os2, const void *head, const void *po if (tt_os2) { USHORT version = GET_BE_WORD(tt_os2->version); - metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent); - metrics->descent = GET_BE_WORD(tt_os2->usWinDescent); - /* FIXME: sTypoLineGap should only be used when USE_TYPO_METRICS is set, - if not set this value is probably derived from other metrics */ - metrics->lineGap = GET_BE_WORD(tt_os2->sTypoLineGap); + metrics->ascent = GET_BE_WORD(tt_os2->usWinAscent); + metrics->descent = GET_BE_WORD(tt_os2->usWinDescent); + + /* line gap is estimated using two sets of ascender/descender values and 'hhea' line gap */ + if (tt_hhea) { + SHORT descender = (SHORT)GET_BE_WORD(tt_hhea->descender); + INT32 linegap; + + linegap = GET_BE_WORD(tt_hhea->ascender) + abs(descender) + GET_BE_WORD(tt_hhea->linegap) - + metrics->ascent - metrics->descent; + metrics->lineGap = linegap > 0 ? linegap : 0; + } + metrics->strikethroughPosition = GET_BE_WORD(tt_os2->yStrikeoutPosition); metrics->strikethroughThickness = GET_BE_WORD(tt_os2->yStrikeoutSize); metrics->subscriptPositionX = GET_BE_WORD(tt_os2->ySubscriptXOffset); @@ -935,6 +973,15 @@ void opentype_get_font_metrics(const void *os2, const void *head, const void *po metrics->xHeight = metrics->designUnitsPerEm / 2; if (metrics->capHeight == 0) metrics->capHeight = metrics->designUnitsPerEm * 7 / 10; + + if (tt_os2) + IDWriteFontFileStream_ReleaseFileFragment(stream, os2_context); + if (tt_head) + IDWriteFontFileStream_ReleaseFileFragment(stream, head_context); + if (tt_post) + IDWriteFontFileStream_ReleaseFileFragment(stream, post_context); + if (tt_hhea) + IDWriteFontFileStream_ReleaseFileFragment(stream, hhea_context); } void opentype_get_font_properties(const void *os2, const void *head, DWRITE_FONT_STRETCH *stretch, DWRITE_FONT_WEIGHT *weight, DWRITE_FONT_STYLE *style) diff --git a/dlls/dwrite/tests/font.c b/dlls/dwrite/tests/font.c index 3276b6d..2fe845c 100644 --- a/dlls/dwrite/tests/font.c +++ b/dlls/dwrite/tests/font.c @@ -1053,7 +1053,6 @@ if (0) /* crashes on native */ ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm); ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent); ok(metrics.descent != 0, "descent %u\n", metrics.descent); -todo_wine ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap); ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight); ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight); @@ -1071,7 +1070,6 @@ todo_wine ok(metrics.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics.designUnitsPerEm); ok(metrics.ascent != 0, "ascent %u\n", metrics.ascent); ok(metrics.descent != 0, "descent %u\n", metrics.descent); -todo_wine ok(metrics.lineGap == 0, "lineGap %d\n", metrics.lineGap); ok(metrics.capHeight, "capHeight %u\n", metrics.capHeight); ok(metrics.xHeight != 0, "xHeight %u\n", metrics.xHeight); @@ -1091,7 +1089,6 @@ todo_wine ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm); ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent); ok(metrics1.descent != 0, "descent %u\n", metrics1.descent); - todo_wine ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap); ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight); ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight); @@ -1120,7 +1117,6 @@ todo_wine ok(metrics1.designUnitsPerEm != 0, "designUnitsPerEm %u\n", metrics1.designUnitsPerEm); ok(metrics1.ascent != 0, "ascent %u\n", metrics1.ascent); ok(metrics1.descent != 0, "descent %u\n", metrics1.descent); - todo_wine ok(metrics1.lineGap == 0, "lineGap %d\n", metrics1.lineGap); ok(metrics1.capHeight, "capHeight %u\n", metrics1.capHeight); ok(metrics1.xHeight != 0, "xHeight %u\n", metrics1.xHeight); -- 2.1.3