From: Torge Matthies tmatthies@codeweavers.com
This always applies, whether the glyph is passed by unicode code point or by glyph index.
Signed-off-by: Torge Matthies tmatthies@codeweavers.com --- dlls/win32u/font.c | 131 +++++++++++++++++++++++++++++++++++- dlls/win32u/ntgdi_private.h | 2 + 2 files changed, 132 insertions(+), 1 deletion(-)
diff --git a/dlls/win32u/font.c b/dlls/win32u/font.c index 977f079285b..d9d43cdab85 100644 --- a/dlls/win32u/font.c +++ b/dlls/win32u/font.c @@ -2426,6 +2426,7 @@ static void free_gdi_font( struct gdi_font *font ) free( font->gm ); free( font->kern_pairs ); free( font->gsub_table ); + free( font->gdef_table ); free( font ); }
@@ -2833,6 +2834,126 @@ static UINT get_GSUB_vert_glyph( struct gdi_font *font, UINT glyph ) return GSUB_apply_feature( font->gsub_table, font->vert_feature, glyph ); }
+/* structures copied from dlls/gdi32/uniscribe/opentype.c */ + +enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph}; + +typedef struct { + DWORD Version; + WORD GlyphClassDef; + WORD AttachList; + WORD LigCaretList; + WORD MarkAttachClassDef; +} GDEF_Header; + +typedef struct { + WORD ClassFormat; + WORD StartGlyph; + WORD GlyphCount; + WORD ClassValueArray[1]; +} OT_ClassDefFormat1; + +typedef struct { + WORD Start; + WORD End; + WORD Class; +} OT_ClassRangeRecord; + +typedef struct { + WORD ClassFormat; + WORD ClassRangeCount; + OT_ClassRangeRecord ClassRangeRecord[1]; +} OT_ClassDefFormat2; + +static void *load_GDEF( struct gdi_font *font ) +{ + WORD format, offset, count; + GDEF_Header hdr; + UINT result; + size_t size; + void *data; + + result = font_funcs->get_font_data( font, MS_GDEF_TAG, 0, &hdr, sizeof(hdr) ); + if (result == GDI_ERROR) /* no GDEF table present */ + { + TRACE("No GDEF table found\n"); + return NULL; + } + + offset = GET_BE_WORD(hdr.GlyphClassDef); + if (!offset) + return NULL; + + result = font_funcs->get_font_data( font, MS_GDEF_TAG, offset, &format, sizeof(format) ); + format = GET_BE_WORD(format); + if (result == GDI_ERROR || format < 1 || format > 2) /* GDEF table invalid or too short */ + { + WARN("Invalid GDEF table\n"); + return NULL; + } + + if (format == 1) + { + result = font_funcs->get_font_data( font, MS_GDEF_TAG, offset + 4, &count, sizeof(count) ); + size = FIELD_OFFSET(OT_ClassDefFormat1, ClassValueArray[GET_BE_WORD(count)]); + } + else + { + result = font_funcs->get_font_data( font, MS_GDEF_TAG, offset + 2, &count, sizeof(count) ); + size = FIELD_OFFSET(OT_ClassDefFormat2, ClassRangeRecord[GET_BE_WORD(count)]); + } + if (result == GDI_ERROR) + return NULL; + + data = malloc( size ); + if (!data) + return NULL; + + result = font_funcs->get_font_data( font, MS_GDEF_TAG, offset, data, size ); + if (result != GDI_ERROR) + { + TRACE( "Loaded GDEF table of %zu bytes\n", size ); + return data; + } + else + free( data ); + return NULL; +} + +static WORD get_GDEF_glyph_class( struct gdi_font *font, WORD glyph ) +{ + OT_ClassDefFormat1 *cf1 = font->gdef_table; + WORD class = 0; + + if (!cf1) + return 0; + + if (cf1->ClassFormat == 1) + { + if (glyph >= GET_BE_WORD(cf1->StartGlyph)) + { + int index = glyph - GET_BE_WORD(cf1->StartGlyph); + if (index < GET_BE_WORD(cf1->GlyphCount)) + class = GET_BE_WORD(cf1->ClassValueArray[index]); + } + } + else + { + OT_ClassDefFormat2 *cf2 = (OT_ClassDefFormat2 *)cf1; + int i, top = GET_BE_WORD(cf2->ClassRangeCount); + for (i = 0; i < top; i++) + { + if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) && + glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End)) + { + class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class); + break; + } + } + } + return class; +} + static void add_child_font( struct gdi_font *font, const WCHAR *family_name ) { FONTSIGNATURE fs = {{0}}; @@ -3936,16 +4057,22 @@ static DWORD get_glyph_outline( struct gdi_font *font, UINT glyph, UINT format, }
if (format == GGO_METRICS && !mat && get_gdi_font_glyph_metrics( font, index, &gm, &abc )) + { + if (zero_width && (abc.abcA + abc.abcB + abc.abcC == 0)) + *zero_width = get_GDEF_glyph_class( font, index ); goto done; + }
ret = font_funcs->get_glyph_outline( font, index, format, &gm, &abc, buflen, buf, mat, tategaki ); if (ret == GDI_ERROR) return ret;
+ if (zero_width && (abc.abcA + abc.abcB + abc.abcC == 0)) + *zero_width = get_GDEF_glyph_class( font, index ); + if (format == GGO_METRICS && !mat) set_gdi_font_glyph_metrics( font, index, &gm, &abc );
done: - if (zero_width && (abc.abcA + abc.abcB + abc.abcC) == 0) *zero_width = TRUE; if (gm_ret) *gm_ret = gm; if (abc_ret) *abc_ret = abc; return ret; @@ -4663,6 +4790,8 @@ static struct gdi_font *select_font( LOGFONTW *lf, FMAT2 dcmat, BOOL can_use_bit if (face->flags & ADDFONT_VERTICAL_FONT) /* We need to try to load the GSUB table */ font->vert_feature = get_GSUB_vert_feature( font );
+ font->gdef_table = load_GDEF( font ); + create_child_font_list( font );
TRACE( "caching: gdiFont=%p\n", font ); diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index ad4c709b865..de0fa071817 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -288,6 +288,7 @@ struct gdi_font struct gdi_font *base_font; void *gsub_table; void *vert_feature; + void *gdef_table; void *data_ptr; SIZE_T data_size; FILETIME writetime; @@ -299,6 +300,7 @@ struct gdi_font
#define MS_GASP_TAG MS_MAKE_TAG('g', 'a', 's', 'p') #define MS_GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B') +#define MS_GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F') #define MS_KERN_TAG MS_MAKE_TAG('k', 'e', 'r', 'n') #define MS_TTCF_TAG MS_MAKE_TAG('t', 't', 'c', 'f') #define MS_VDMX_TAG MS_MAKE_TAG('V', 'D', 'M', 'X')