Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 2 + dlls/dwrite/dwrite_private.h | 7 ++ dlls/dwrite/opentype.c | 127 ++++++++++++++++++++++++++++++++++- dlls/dwrite/shape.c | 1 + 4 files changed, 136 insertions(+), 1 deletion(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 13c1941d75..7f15c91279 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -1313,6 +1313,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGlyphPlacements(IDWriteTextAnalyzer2 context.text = text; context.length = text_len; context.is_rtl = is_rtl; + context.u.pos.glyphs = glyphs; context.u.pos.glyph_props = glyph_props; context.glyph_count = glyph_count; context.advances = advances; @@ -1374,6 +1375,7 @@ static HRESULT WINAPI dwritetextanalyzer_GetGdiCompatibleGlyphPlacements(IDWrite context.text = text; context.length = text_len; context.is_rtl = is_rtl; + context.u.pos.glyphs = glyphs; context.u.pos.glyph_props = glyph_props; context.glyph_count = glyph_count; context.advances = advances; diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index b7d5d4583c..5a6cd4b16b 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -366,6 +366,12 @@ struct scriptshaping_cache unsigned int feature_list; unsigned int lookup_list; } gpos; + + struct + { + struct dwrite_fonttable table; + unsigned int classdef; + } gdef; };
struct scriptshaping_context @@ -381,6 +387,7 @@ struct scriptshaping_context { struct { + const UINT16 *glyphs; const DWRITE_SHAPING_GLYPH_PROPERTIES *glyph_props; } pos; } u; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index b360bbb009..8cc74638b0 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -32,6 +32,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dwrite); #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') +#define MS_GDEF_TAG DWRITE_MAKE_OPENTYPE_TAG('G','D','E','F') #define MS_GPOS_TAG DWRITE_MAKE_OPENTYPE_TAG('G','P','O','S') #define MS_GSUB_TAG DWRITE_MAKE_OPENTYPE_TAG('G','S','U','B') #define MS_NAME_TAG DWRITE_MAKE_OPENTYPE_TAG('n','a','m','e') @@ -416,6 +417,47 @@ struct ot_script_list struct ot_script_record scripts[1]; };
+enum ot_gdef_class +{ + GDEF_CLASS_UNCLASSIFIED = 0, + GDEF_CLASS_BASE = 1, + GDEF_CLASS_LIGATURE = 2, + GDEF_CLASS_MARK = 3, + GDEF_CLASS_COMPONENT = 4, + GDEF_CLASS_MAX = GDEF_CLASS_COMPONENT, +}; + +struct gdef_header +{ + DWORD version; + WORD classdef; + WORD attach_list; + WORD ligcaret_list; + WORD markattach_classdef; +}; + +struct ot_gdef_classdef_format1 +{ + WORD format; + WORD start_glyph; + WORD glyph_count; + WORD classes[1]; +}; + +struct ot_gdef_class_range +{ + WORD start_glyph; + WORD end_glyph; + WORD glyph_class; +}; + +struct ot_gdef_classdef_format2 +{ + WORD format; + WORD range_count; + struct ot_gdef_class_range ranges[1]; +}; + struct gpos_gsub_header { DWORD version; @@ -424,6 +466,16 @@ struct gpos_gsub_header WORD lookup_list; };
+enum gsub_gpos_lookup_flags +{ + LOOKUP_FLAG_RTL = 0x1, + LOOKUP_FLAG_IGNORE_BASE = 0x2, + LOOKUP_FLAG_IGNORE_LIGATURES = 0x4, + LOOKUP_FLAG_IGNORE_MARKS = 0x8, + + LOOKUP_FLAG_IGNORE_MASK = 0xe, +}; + enum gpos_lookup_type { GPOS_LOOKUP_SINGLE_ADJUSTMENT = 1, @@ -2447,6 +2499,12 @@ void opentype_layout_scriptshaping_cache_init(struct scriptshaping_cache *cache) cache->gpos.lookup_list = table_read_be_word(&cache->gpos.table, FIELD_OFFSET(struct gpos_gsub_header, lookup_list)); } + + cache->font->grab_font_table(cache->context, MS_GDEF_TAG, &cache->gdef.table.data, &cache->gdef.table.size, + &cache->gdef.table.context); + + if (cache->gdef.table.data) + cache->gdef.classdef = table_read_be_word(&cache->gdef.table, FIELD_OFFSET(struct gdef_header, classdef)); }
DWORD opentype_layout_find_script(const struct scriptshaping_cache *cache, DWORD kind, DWORD script, @@ -2519,6 +2577,64 @@ DWORD opentype_layout_find_language(const struct scriptshaping_cache *cache, DWO return 0; }
+static int gdef_class_compare_format2(const void *g, const void *r) +{ + const struct ot_gdef_class_range *range = r; + UINT16 glyph = *(UINT16 *)g; + + if (glyph < GET_BE_WORD(range->start_glyph)) + return -1; + else if (glyph > GET_BE_WORD(range->end_glyph)) + return 1; + else + return 0; +} + +static unsigned int opentype_layout_get_glyph_class(const struct dwrite_fonttable *table, + unsigned int offset, UINT16 glyph) +{ + WORD format = table_read_be_word(table, offset), count; + unsigned int glyph_class = GDEF_CLASS_UNCLASSIFIED; + + if (format == 1) + { + const struct ot_gdef_classdef_format1 *format1; + + count = table_read_be_word(table, offset + FIELD_OFFSET(struct ot_gdef_classdef_format1, glyph_count)); + format1 = table_read_ensure(table, offset, FIELD_OFFSET(struct ot_gdef_classdef_format1, classes[count])); + if (format1) + { + WORD start_glyph = GET_BE_WORD(format1->start_glyph); + if (glyph >= start_glyph && (glyph - start_glyph) < count) + { + glyph_class = GET_BE_WORD(format1->classes[glyph - start_glyph]); + if (glyph_class > GDEF_CLASS_MAX) + glyph_class = GDEF_CLASS_UNCLASSIFIED; + } + } + } + else if (format == 2) + { + const struct ot_gdef_classdef_format2 *format2; + + count = table_read_be_word(table, offset + FIELD_OFFSET(struct ot_gdef_classdef_format2, range_count)); + format2 = table_read_ensure(table, offset, FIELD_OFFSET(struct ot_gdef_classdef_format2, ranges[count])); + if (format2) + { + const struct ot_gdef_class_range *range = bsearch(&glyph, format2->ranges, count, + sizeof(struct ot_gdef_class_range), gdef_class_compare_format2); + glyph_class = range && glyph <= GET_BE_WORD(range->end_glyph) ? + GET_BE_WORD(range->glyph_class) : GDEF_CLASS_UNCLASSIFIED; + if (glyph_class > GDEF_CLASS_MAX) + glyph_class = GDEF_CLASS_UNCLASSIFIED; + } + } + else + WARN("Unknown GDEF format %u.\n", format); + + return glyph_class; +} + struct lookup { unsigned int offset; @@ -2545,7 +2661,16 @@ static void glyph_iterator_init(const struct scriptshaping_context *context, uns
static BOOL glyph_iterator_match(const struct glyph_iterator *iter) { - /* FIXME: implement class matching */ + struct scriptshaping_cache *cache = iter->context->cache; + + if (cache->gdef.classdef) + { + unsigned int glyph_class = opentype_layout_get_glyph_class(&cache->gdef.table, cache->gdef.classdef, + iter->context->u.pos.glyphs[iter->pos]); + if ((1 << glyph_class) & iter->flags & LOOKUP_FLAG_IGNORE_MASK) + return FALSE; + } + return TRUE; }
diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index 831c7754fc..d7d1261f35 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -51,6 +51,7 @@ void release_scriptshaping_cache(struct scriptshaping_cache *cache) if (!cache) return;
+ cache->font->release_font_table(cache->context, cache->gdef.table.context); cache->font->release_font_table(cache->context, cache->gpos.table.context); heap_free(cache); }