Skip to content

Commit

Permalink
gdiplus: Search microsoft platform names first in load_ttf_name_id().
Browse files Browse the repository at this point in the history
Search names in fonts in the order of Microsoft, Mac and finally Unicode platform. This is also the
order win32u uses to load font names.

Fix Granado Espada Japan (1219160) launcher crashes at start in the Japanese locale. The game ships
a font with a broken name record of Mac platform and encoding ID 0 (Roman) but the name string is in
code page 10001 (Japanese). This broken name record is placed before the name records for the
Microsoft platform so it gets selected first. Then the name string in the name record doesn't get
converted correctly to Unicode because of the wrong code page. Thus the EnumFontFamiliesExW()
in GdipPrivateAddMemoryFont() fails to find the font and causes game crash.

(cherry picked from commit 9786ee2)

CW-Bug-Id: #23597
  • Loading branch information
zzhiyi authored and ivyl committed May 23, 2024
1 parent 9fbaa06 commit 42c2d33
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 16 deletions.
38 changes: 23 additions & 15 deletions dlls/gdiplus/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -1385,12 +1385,13 @@ static WCHAR *copy_name_table_string( const tt_name_record *name, const BYTE *da

static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id )
{
static const WORD platform_id_table[] = {TT_PLATFORM_MICROSOFT, TT_PLATFORM_MACINTOSH, TT_PLATFORM_APPLE_UNICODE};
LANGID lang = GetSystemDefaultLangID();
const tt_header *header;
const tt_name_table *name_table;
const tt_name_record *name_record;
const tt_name_record *name_record_table, *name_record;
DWORD pos, ofs = 0, count;
int i, res, best_lang = 0, best_index = -1;
int i, j, res, best_lang = 0, best_index = -1;

if (sizeof(tt_header) > size)
return NULL;
Expand Down Expand Up @@ -1421,26 +1422,33 @@ static WCHAR *load_ttf_name_id( const BYTE *mem, DWORD_PTR size, DWORD id )
if (pos > size)
return NULL;
name_table = (const tt_name_table*)&mem[ofs];
name_record_table = (const tt_name_record *)&mem[pos];
count = GET_BE_WORD(name_table->count);
if (GET_BE_WORD(name_table->string_offset) >= size - ofs) return NULL;
ofs += GET_BE_WORD(name_table->string_offset);
for (i=0; i<count; i++)
for (i = 0; i < ARRAY_SIZE(platform_id_table); i++)
{
name_record = (const tt_name_record*)&mem[pos];
pos += sizeof(*name_record);
if (pos > size)
return NULL;
for (j = 0; j < count; j++)
{
name_record = name_record_table + j;
if ((const BYTE *)name_record - mem > size)
return NULL;

if (GET_BE_WORD(name_record->name_id) != id) continue;
if (GET_BE_WORD(name_record->offset) >= size - ofs) return NULL;
if (GET_BE_WORD(name_record->length) > size - ofs - GET_BE_WORD(name_record->offset)) return NULL;
if (GET_BE_WORD(name_record->platform_id) != platform_id_table[i]) continue;
if (GET_BE_WORD(name_record->name_id) != id) continue;
if (GET_BE_WORD(name_record->offset) >= size - ofs) return NULL;
if (GET_BE_WORD(name_record->length) > size - ofs - GET_BE_WORD(name_record->offset)) return NULL;

res = match_name_table_language( name_record, lang );
if (res > best_lang)
{
best_lang = res;
best_index = i;
res = match_name_table_language(name_record, lang);
if (res > best_lang)
{
best_lang = res;
best_index = j;
}
}

if (best_index != -1)
break;
}

if (best_lang)
Expand Down
1 change: 0 additions & 1 deletion dlls/gdiplus/tests/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -1558,7 +1558,6 @@ static void test_GdipPrivateAddMemoryFont(void)
{
stat = GdipGetFontCollectionFamilyCount(fonts, &count);
ok(stat == Ok, "GdipGetFontCollectionFamilyCount failed, error %d\n", stat);
todo_wine
ok(count == 1, "Expected count 1, got %d\n", count);
}
else if (i == 1 && stat == FileNotFound)
Expand Down

0 comments on commit 42c2d33

Please sign in to comment.