Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 3 +++ dlls/dwrite/opentype.c | 23 +++++++++++++++-------- dlls/dwrite/shape.c | 12 ++++++------ 3 files changed, 24 insertions(+), 14 deletions(-)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 7c9fe8a6873..632b2776bfc 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -615,6 +615,9 @@ enum shaping_feature_flags { FEATURE_GLOBAL = 0x1, FEATURE_GLOBAL_SEARCH = 0x2, + FEATURE_MANUAL_ZWNJ = 0x4, + FEATURE_MANUAL_ZWJ = 0x8, + FEATURE_MANUAL_JOINERS = FEATURE_MANUAL_ZWNJ | FEATURE_MANUAL_ZWJ, };
struct shaping_feature diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 260a0a8f5db..55ef482c42d 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3508,6 +3508,8 @@ struct lookup
unsigned int mask; unsigned int offset; + unsigned int auto_zwnj : 1; + unsigned int auto_zwj : 1; };
static unsigned int opentype_layout_get_gsubgpos_subtable(const struct scriptshaping_context *context, @@ -4337,8 +4339,8 @@ static int lookups_sorting_compare(const void *a, const void *b) return left->index < right->index ? -1 : left->index > right->index ? 1 : 0; };
-static BOOL opentype_layout_init_lookup(const struct ot_gsubgpos_table *table, unsigned short lookup_index, unsigned int mask, - struct lookup *lookup) +static BOOL opentype_layout_init_lookup(const struct ot_gsubgpos_table *table, unsigned short lookup_index, + const struct shaping_feature *feature, struct lookup *lookup) { unsigned short subtable_count, lookup_type, flags, mark_filtering_set; const struct ot_lookup_table *lookup_table; @@ -4372,8 +4374,13 @@ static BOOL opentype_layout_init_lookup(const struct ot_gsubgpos_table *table, u lookup->type = lookup_type; lookup->flags = flags; lookup->subtable_count = subtable_count; - lookup->mask = mask; lookup->offset = offset; + if (feature) + { + lookup->mask = feature->mask; + lookup->auto_zwnj = !(feature->flags & FEATURE_MANUAL_ZWNJ); + lookup->auto_zwj = !(feature->flags & FEATURE_MANUAL_ZWJ); + }
return TRUE; } @@ -4409,7 +4416,7 @@ static void opentype_layout_add_lookups(const struct ot_feature_list *feature_li if (lookup_index >= total_lookup_count) continue;
- if (opentype_layout_init_lookup(table, lookup_index, feature->mask, &lookups->lookups[lookups->count])) + if (opentype_layout_init_lookup(table, lookup_index, feature, &lookups->lookups[lookups->count])) lookups->count++; } } @@ -4567,6 +4574,8 @@ static void opentype_layout_collect_lookups(struct scriptshaping_context *contex else { lookups->lookups[j].mask |= lookups->lookups[i].mask; + lookups->lookups[j].auto_zwnj &= lookups->lookups[i].auto_zwnj; + lookups->lookups[j].auto_zwj &= lookups->lookups[i].auto_zwj; } } lookups->count = j + 1; @@ -4648,8 +4657,7 @@ static void opentype_layout_set_glyph_masks(struct scriptshaping_context *contex static void opentype_layout_apply_gpos_context_lookup(struct scriptshaping_context *context, unsigned int lookup_index) { struct lookup lookup = { 0 }; - /* Feature mask is intentionally zero, it's not used outside of main loop. */ - if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) + if (opentype_layout_init_lookup(context->table, lookup_index, NULL, &lookup)) opentype_layout_apply_gpos_lookup(context, &lookup); }
@@ -5742,8 +5750,7 @@ static BOOL opentype_is_gsub_lookup_reversed(const struct scriptshaping_context static void opentype_layout_apply_gsub_context_lookup(struct scriptshaping_context *context, unsigned int lookup_index) { struct lookup lookup = { 0 }; - /* Feature mask is intentionally zero, it's not used outside of main loop. */ - if (opentype_layout_init_lookup(context->table, lookup_index, 0, &lookup)) + if (opentype_layout_init_lookup(context->table, lookup_index, NULL, &lookup)) opentype_layout_apply_gsub_lookup(context, &lookup); }
diff --git a/dlls/dwrite/shape.c b/dlls/dwrite/shape.c index be8a69c27c4..567ec5fa54f 100644 --- a/dlls/dwrite/shape.c +++ b/dlls/dwrite/shape.c @@ -189,12 +189,12 @@ static void shape_merge_features(struct scriptshaping_context *context, struct s
HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigned int *scripts) { - static const unsigned int common_features[] = + static const struct shaping_feature common_features[] = { - DWRITE_MAKE_OPENTYPE_TAG('a','b','v','m'), - DWRITE_MAKE_OPENTYPE_TAG('b','l','w','m'), - DWRITE_MAKE_OPENTYPE_TAG('m','a','r','k'), - DWRITE_MAKE_OPENTYPE_TAG('m','k','m','k'), + { DWRITE_MAKE_OPENTYPE_TAG('a','b','v','m') }, + { DWRITE_MAKE_OPENTYPE_TAG('b','l','w','m') }, + { DWRITE_MAKE_OPENTYPE_TAG('m','a','r','k'), FEATURE_MANUAL_JOINERS }, + { DWRITE_MAKE_OPENTYPE_TAG('m','k','m','k'), FEATURE_MANUAL_JOINERS }, }; static const unsigned int horizontal_features[] = { @@ -207,7 +207,7 @@ HRESULT shape_get_positions(struct scriptshaping_context *context, const unsigne struct shaping_features features = { 0 };
for (i = 0; i < ARRAY_SIZE(common_features); ++i) - shape_add_feature(&features, common_features[i]); + shape_add_feature_full(&features, common_features[i].tag, FEATURE_GLOBAL | common_features[i].flags, 1);
/* Horizontal features */ if (!context->is_sideways)
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/dwrite_private.h | 2 ++ dlls/dwrite/opentype.c | 11 +++++++++++ 2 files changed, 13 insertions(+)
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index 632b2776bfc..f3636876251 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -585,6 +585,8 @@ struct scriptshaping_context } user_features; unsigned int global_mask; unsigned int lookup_mask; /* Currently processed feature mask, set in main loop. */ + unsigned int auto_zwj; + unsigned int auto_zwnj; struct shaping_glyph_info *glyph_infos;
unsigned int cur; diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 55ef482c42d..aedbfe6dcab 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -3587,6 +3587,8 @@ struct glyph_iterator p_match_func match_func; const UINT16 *glyph_data; const struct match_data *match_data; + unsigned int ignore_zwnj; + unsigned int ignore_zwj; };
static void glyph_iterator_init(struct scriptshaping_context *context, unsigned int flags, unsigned int pos, @@ -3600,6 +3602,9 @@ static void glyph_iterator_init(struct scriptshaping_context *context, unsigned iter->match_func = NULL; iter->match_data = NULL; iter->glyph_data = NULL; + /* Context matching iterators will get these fixed up. */ + iter->ignore_zwnj = context->table == &context->cache->gpos; + iter->ignore_zwj = context->auto_zwj; }
struct ot_gdef_mark_glyph_sets @@ -4682,6 +4687,8 @@ void opentype_layout_apply_gpos_features(struct scriptshaping_context *context,
context->cur = 0; context->lookup_mask = lookup->mask; + context->auto_zwnj = lookup->auto_zwnj; + context->auto_zwj = lookup->auto_zwj;
while (context->cur < context->glyph_count) { @@ -5092,6 +5099,8 @@ static BOOL opentype_layout_context_match_backtrack(const struct match_context * iter.match_func = mc->match_func; iter.match_data = &match_data; iter.glyph_data = backtrack; + iter.ignore_zwnj |= context->auto_zwnj; + iter.ignore_zwj = 1;
for (i = 0; i < count; ++i) { @@ -5116,6 +5125,8 @@ static BOOL opentype_layout_context_match_lookahead(const struct match_context * iter.match_func = mc->match_func; iter.match_data = &match_data; iter.glyph_data = lookahead; + iter.ignore_zwnj |= context->auto_zwnj; + iter.ignore_zwj = 1;
for (i = 0; i < count; ++i) {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index aedbfe6dcab..5698a83f3bf 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -479,6 +479,8 @@ enum glyph_prop_flags GLYPH_PROP_BASE = LOOKUP_FLAG_IGNORE_BASE, GLYPH_PROP_LIGATURE = LOOKUP_FLAG_IGNORE_LIGATURES, GLYPH_PROP_MARK = LOOKUP_FLAG_IGNORE_MARKS, + GLYPH_PROP_ZWNJ = 0x10, + GLYPH_PROP_ZWJ = 0x20, };
enum gpos_lookup_type @@ -3683,6 +3685,10 @@ static enum iterator_match glyph_iterator_may_skip(const struct glyph_iterator * if (!lookup_is_glyph_match(iter->context, iter->pos, iter->flags)) return ITER_YES;
+ if ((iter->ignore_zwnj || !(iter->context->glyph_infos[iter->pos].props & GLYPH_PROP_ZWNJ)) && + (iter->ignore_zwj || !(iter->context->glyph_infos[iter->pos].props & GLYPH_PROP_ZWJ))) + return ITER_MAYBE; + return ITER_NO; }
@@ -5723,6 +5729,10 @@ static void opentype_get_nominal_glyphs(struct scriptshaping_context *context, c context->u.buffer.glyphs[g] = font->get_glyph(context->cache->context, codepoint); context->u.buffer.glyph_props[g].justification = SCRIPT_JUSTIFY_CHARACTER; opentype_set_subst_glyph_props(context, g); + if (codepoint == 0x200d) + context->glyph_infos[g].props |= GLYPH_PROP_ZWJ; + else if (codepoint == 0x200c) + context->glyph_infos[g].props |= GLYPH_PROP_ZWNJ;
/* Group diacritics with preceding base. Glyph class is ignored here. */ if (!g || !opentype_is_diacritic(codepoint))
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index 5698a83f3bf..ff341f03232 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -5794,6 +5794,8 @@ void opentype_layout_apply_gsub_features(struct scriptshaping_context *context, const struct lookup *lookup = &lookups.lookups[i];
context->lookup_mask = lookup->mask; + context->auto_zwnj = lookup->auto_zwnj; + context->auto_zwj = lookup->auto_zwj;
if (!opentype_is_gsub_lookup_reversed(context, lookup)) {
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/opentype.c | 115 ++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 53 deletions(-)
diff --git a/dlls/dwrite/opentype.c b/dlls/dwrite/opentype.c index ff341f03232..7c30678234a 100644 --- a/dlls/dwrite/opentype.c +++ b/dlls/dwrite/opentype.c @@ -320,21 +320,23 @@ enum OS2_FSSELECTION { OS2_FSSELECTION_OBLIQUE = 1 << 9 };
-typedef struct { +struct name_record +{ WORD platformID; WORD encodingID; WORD languageID; WORD nameID; WORD length; WORD offset; -} TT_NameRecord; +};
-typedef struct { +struct name_header +{ WORD format; WORD count; WORD stringOffset; - TT_NameRecord nameRecord[1]; -} TT_NAME_V0; + struct name_record records[1]; +};
struct vdmx_header { @@ -2278,11 +2280,19 @@ static void get_name_record_locale(enum OPENTYPE_PLATFORM_ID platform, USHORT la } }
-static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_area, USHORT recid, IDWriteLocalizedStrings *strings) +static BOOL opentype_decode_namerecord(const struct dwrite_fonttable *table, unsigned int idx, + IDWriteLocalizedStrings *strings) { - const TT_NameRecord *record = &header->nameRecord[recid]; USHORT lang_id, length, offset, encoding, platform; + const struct name_header *header = (const struct name_header *)table->data; + const struct name_record *record; + unsigned int i, string_offset; BOOL ret = FALSE; + const void *name; + + string_offset = table_read_be_word(table, FIELD_OFFSET(struct name_header, stringOffset)); + + record = &header->records[idx];
platform = GET_BE_WORD(record->platformID); lang_id = GET_BE_WORD(record->languageID); @@ -2290,7 +2300,11 @@ static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_a offset = GET_BE_WORD(record->offset); encoding = GET_BE_WORD(record->encodingID);
- if (lang_id < 0x8000) { + if (!(name = table_read_ensure(table, string_offset + offset, length))) + return FALSE; + + if (lang_id < 0x8000) + { WCHAR locale[LOCALE_NAME_MAX_LENGTH]; WCHAR *name_string; UINT codepage; @@ -2298,17 +2312,17 @@ static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_a codepage = get_name_record_codepage(platform, encoding); get_name_record_locale(platform, lang_id, locale, ARRAY_SIZE(locale));
- if (codepage) { - DWORD len = MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, NULL, 0); + if (codepage) + { + DWORD len = MultiByteToWideChar(codepage, 0, name, length, NULL, 0); name_string = heap_alloc(sizeof(WCHAR) * (len+1)); - MultiByteToWideChar(codepage, 0, (LPSTR)(storage_area + offset), length, name_string, len); + MultiByteToWideChar(codepage, 0, name, length, name_string, len); name_string[len] = 0; } - else { - int i; - + else + { length /= sizeof(WCHAR); - name_string = heap_strdupnW((LPWSTR)(storage_area + offset), length); + name_string = heap_strdupnW(name, length); for (i = 0; i < length; i++) name_string[i] = GET_BE_WORD(name_string[i]); } @@ -2324,45 +2338,45 @@ static BOOL opentype_decode_namerecord(const TT_NAME_V0 *header, BYTE *storage_a return ret; }
-static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OPENTYPE_STRING_ID id, IDWriteLocalizedStrings **strings) +static HRESULT opentype_get_font_strings_from_id(const struct dwrite_fonttable *table, enum OPENTYPE_STRING_ID id, + IDWriteLocalizedStrings **strings) { int i, count, candidate_mac, candidate_unicode; - const TT_NAME_V0 *header; - BYTE *storage_area = 0; + const struct name_record *records; WORD format; BOOL exists; HRESULT hr;
- if (!table_data) + if (!table->data) return E_FAIL;
- hr = create_localizedstrings(strings); - if (FAILED(hr)) return hr; + if (FAILED(hr = create_localizedstrings(strings))) + return hr;
- header = table_data; - format = GET_BE_WORD(header->format); + format = table_read_be_word(table, FIELD_OFFSET(struct name_header, format));
- switch (format) { - case 0: - case 1: - break; - default: + if (format != 0 && format != 1) FIXME("unsupported NAME format %d\n", format); - }
- storage_area = (LPBYTE)table_data + GET_BE_WORD(header->stringOffset); - count = GET_BE_WORD(header->count); + count = table_read_be_word(table, FIELD_OFFSET(struct name_header, count)); + + if (!(records = table_read_ensure(table, FIELD_OFFSET(struct name_header, records), + count * sizeof(struct name_record)))) + { + count = 0; + }
exists = FALSE; candidate_unicode = candidate_mac = -1; - for (i = 0; i < count; i++) { - const TT_NameRecord *record = &header->nameRecord[i]; - USHORT platform;
- if (GET_BE_WORD(record->nameID) != id) + for (i = 0; i < count; i++) + { + unsigned short platform; + + if (GET_BE_WORD(records[i].nameID) != id) continue;
- platform = GET_BE_WORD(record->platformID); + platform = GET_BE_WORD(records[i].platformID); switch (platform) { /* Skip Unicode or Mac entries for now, fonts tend to duplicate those @@ -2378,7 +2392,7 @@ static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OP candidate_mac = i; break; case OPENTYPE_PLATFORM_WIN: - if (opentype_decode_namerecord(header, storage_area, i, *strings)) + if (opentype_decode_namerecord(table, i, *strings)) exists = TRUE; break; default: @@ -2390,9 +2404,9 @@ static HRESULT opentype_get_font_strings_from_id(const void *table_data, enum OP if (!exists) { if (candidate_mac != -1) - exists = opentype_decode_namerecord(header, storage_area, candidate_mac, *strings); + exists = opentype_decode_namerecord(table, candidate_mac, *strings); if (!exists && candidate_unicode != -1) - exists = opentype_decode_namerecord(header, storage_area, candidate_unicode, *strings); + exists = opentype_decode_namerecord(table, candidate_unicode, *strings);
if (!exists) { @@ -2527,7 +2541,7 @@ HRESULT opentype_get_font_info_strings(const struct file_stream_desc *stream_des break; default: opentype_get_font_table(stream_desc, MS_NAME_TAG, &name); - opentype_get_font_strings_from_id(name.data, dwriteid_to_opentypeid[id], strings); + opentype_get_font_strings_from_id(&name, dwriteid_to_opentypeid[id], strings); if (name.context) IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, name.context); } @@ -2540,28 +2554,25 @@ HRESULT opentype_get_font_info_strings(const struct file_stream_desc *stream_des HRESULT opentype_get_font_familyname(struct file_stream_desc *stream_desc, IDWriteLocalizedStrings **names) { struct dwrite_fonttable os2, name; - const void *name_table; UINT16 fsselection; HRESULT hr;
opentype_get_font_table(stream_desc, MS_OS2_TAG, &os2); opentype_get_font_table(stream_desc, MS_NAME_TAG, &name);
- name_table = (const void *)name.data; - *names = NULL;
/* If Preferred Family doesn't conform to WWS model try WWS name. */ fsselection = os2.data ? table_read_be_word(&os2, FIELD_OFFSET(struct tt_os2, fsSelection)) : 0; if (os2.data && !(fsselection & OS2_FSSELECTION_WWS)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_FAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_WWS_FAMILY_NAME, names); else hr = E_FAIL;
if (FAILED(hr)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_TYPOGRAPHIC_FAMILY_NAME, names); if (FAILED(hr)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_FAMILY_NAME, names);
if (os2.context) IDWriteFontFileStream_ReleaseFileFragment(stream_desc->stream, os2.context); @@ -2577,32 +2588,30 @@ HRESULT opentype_get_font_facename(struct file_stream_desc *stream_desc, WCHAR * { struct dwrite_fonttable os2, name; IDWriteLocalizedStrings *lfnames; - const void *name_table; UINT16 fsselection; HRESULT hr;
opentype_get_font_table(stream_desc, MS_OS2_TAG, &os2); opentype_get_font_table(stream_desc, MS_NAME_TAG, &name);
- name_table = name.data; - *names = NULL;
/* if Preferred Family doesn't conform to WWS model try WWS name */ fsselection = os2.data ? table_read_be_word(&os2, FIELD_OFFSET(struct tt_os2, fsSelection)) : 0; if (os2.data && !(fsselection & OS2_FSSELECTION_WWS)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_WWS_SUBFAMILY_NAME, names); else hr = E_FAIL;
if (FAILED(hr)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_TYPOGRAPHIC_SUBFAMILY_NAME, names); if (FAILED(hr)) - hr = opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_SUBFAMILY_NAME, names); + hr = opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_SUBFAMILY_NAME, names);
/* User locale is preferred, with fallback to en-us. */ *lfname = 0; - if (SUCCEEDED(opentype_get_font_strings_from_id(name_table, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) { + if (SUCCEEDED(opentype_get_font_strings_from_id(&name, OPENTYPE_STRING_FAMILY_NAME, &lfnames))) + { static const WCHAR enusW[] = {'e','n','-','u','s',0}; WCHAR localeW[LOCALE_NAME_MAX_LENGTH]; UINT32 index;