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.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/gdiplus/tests/font.c | 64 +++++++- dlls/gdiplus/tests/resource.rc | 8 + dlls/gdiplus/tests/wine_mac_win.ttf | Bin 0 -> 1140 bytes dlls/gdiplus/tests/wine_mac_win.ttx | 203 ++++++++++++++++++++++++ dlls/gdiplus/tests/wine_unicode_mac.ttf | Bin 0 -> 1168 bytes dlls/gdiplus/tests/wine_unicode_mac.ttx | 203 ++++++++++++++++++++++++ 6 files changed, 471 insertions(+), 7 deletions(-) create mode 100644 dlls/gdiplus/tests/wine_mac_win.ttf create mode 100644 dlls/gdiplus/tests/wine_mac_win.ttx create mode 100644 dlls/gdiplus/tests/wine_unicode_mac.ttf create mode 100644 dlls/gdiplus/tests/wine_unicode_mac.ttx
diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c index 8f0bbce0eb4..6a21ea30361 100644 --- a/dlls/gdiplus/tests/font.c +++ b/dlls/gdiplus/tests/font.c @@ -43,11 +43,21 @@ static void set_rect_empty(RectF *rc) rc->Height = 0.0; }
+#define load_resource(a, b, c) _load_resource(__LINE__, a, b, c) +static void _load_resource(int line, const WCHAR *filename, BYTE **data, DWORD *size) +{ + HRSRC resource = FindResourceW(NULL, filename, (const WCHAR *)RT_RCDATA); + ok_(__FILE__, line)(!!resource, "FindResourceW failed, error %lu\n", GetLastError()); + *data = LockResource(LoadResource(GetModuleHandleW(NULL), resource)); + ok_(__FILE__, line)(!!*data, "LockResource failed, error %lu\n", GetLastError()); + *size = SizeofResource(GetModuleHandleW(NULL), resource); + ok_(__FILE__, line)(*size > 0, "SizeofResource failed, error %lu\n", GetLastError()); +} + static void create_testfontfile(const WCHAR *filename, int resource, WCHAR pathW[MAX_PATH]) { - DWORD written; + DWORD written, length; HANDLE file; - HRSRC res; void *ptr;
GetTempPathW(MAX_PATH, pathW); @@ -56,11 +66,9 @@ static void create_testfontfile(const WCHAR *filename, int resource, WCHAR pathW file = CreateFileW(pathW, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(pathW), GetLastError());
- res = FindResourceA(GetModuleHandleA(NULL), MAKEINTRESOURCEA(resource), (LPCSTR)RT_RCDATA); - ok(res != 0, "couldn't find resource\n"); - ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); - WriteFile(file, ptr, SizeofResource(GetModuleHandleA(NULL), res), &written, NULL); - ok(written == SizeofResource(GetModuleHandleA(NULL), res), "couldn't write resource\n"); + load_resource(MAKEINTRESOURCEW(resource), (BYTE **)&ptr, &length); + WriteFile(file, ptr, length, &written, NULL); + ok(written == length, "couldn't write resource\n"); CloseHandle(file); }
@@ -1524,6 +1532,47 @@ static void test_CloneFont(void) GdipDeleteFontFamily(family); }
+static void test_GdipPrivateAddMemoryFont(void) +{ + static const WORD resource_ids[] = + { + 3, /* A font that has an invalid full name on Mac platform and a valid full name on Microsoft platform */ + 4, /* A font that has an invalid full name on Unicode platform and a valid full name on Mac platform */ + }; + GpFontCollection *fonts; + GpStatus stat; + int count, i; + void *buffer; + DWORD size; + + for (i = 0; i < ARRAY_SIZE(resource_ids); i++) + { + winetest_push_context("test %d", i); + + stat = GdipNewPrivateFontCollection(&fonts); + ok(stat == Ok, "GdipNewPrivateFontCollection failed, error %d\n", stat); + + load_resource(MAKEINTRESOURCEW(resource_ids[i]), (BYTE **)&buffer, &size); + stat = GdipPrivateAddMemoryFont(fonts, buffer, size); + if (stat == Ok) + { + 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) + win_skip("Fonts without Microsoft platform names are unsupported on win7.\n"); + else + ok(0, "GdipPrivateAddMemoryFont failed, error %d\n", stat); + + stat = GdipDeletePrivateFontCollection(&fonts); + ok(stat == Ok, "GdipDeletePrivateFontCollection failed, error %d\n", stat); + + winetest_pop_context(); + } +} + START_TEST(font) { struct GdiplusStartupInput gdiplusStartupInput; @@ -1558,6 +1607,7 @@ START_TEST(font) test_heightgivendpi(); test_GdipGetFontCollectionFamilyList(); test_GdipGetFontCollectionFamilyCount(); + test_GdipPrivateAddMemoryFont();
GdiplusShutdown(gdiplusToken); } diff --git a/dlls/gdiplus/tests/resource.rc b/dlls/gdiplus/tests/resource.rc index 2db8d6359ea..4af61fef65d 100644 --- a/dlls/gdiplus/tests/resource.rc +++ b/dlls/gdiplus/tests/resource.rc @@ -23,3 +23,11 @@
/* @makedep: wine_testfont0.ttf */ 2 RCDATA wine_testfont0.ttf + +/* Generated with: fonttools ttx wine_mac_win.ttx */ +/* @makedep: wine_mac_win.ttf */ +3 RCDATA wine_mac_win.ttf + +/* Generated with: fonttools ttx wine_unicode_mac.ttx */ +/* @makedep: wine_unicode_mac.ttf */ +4 RCDATA wine_unicode_mac.ttf diff --git a/dlls/gdiplus/tests/wine_mac_win.ttf b/dlls/gdiplus/tests/wine_mac_win.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0a0493134deea4cf31e17182df526d9ececd96d2 GIT binary patch literal 1140 zcmds0O=}ZT6g@MOOjB#4%|Z$WnT28tQj=J^kb>1z7j6m>8d{X`F_|xzk1$Qr1O)Rp z6n8EKaak8GM3*j91aT$0bgkmbcwS~~$G_km?!D)ockZ1x?<P<H%wh};C%0~0Y|Kaf zn}D)N_O2C*F6Ol-T#xD3++gI8r>Sok6wel&7v0Jh@gw@0M?(KH^NRQb{j3-EhR1fW zN$HU5QV?5$nWnyGD1~C!#dXw)f6<Ldgm(Gox6|Bz%bLfKXQN-aQTb$^SpR{!5((hm zxo2aUzh0=mmpQW%)C{pkKR<bigH%secFLPFWwb*|R;JtrR;H|4g7O{3`;+3O;sb7; zNwfA5j#}Xfp&wQM)4lCSHa27r-TCd{KzEdfT;w$d6rOBT-H|HZeCpLqvra~;t0=%= zF7TOFPbOS}F+C}<q8~L@<Tw1i0V$N0e{0J8|FMjxhu<w{ncjhd<D6`YRm|XWhP51D zzyhvjd=YbKWmunTIF-UI``yMJIU!;Ni+G-46=l53u$JQsIb6gke9knw<ePDKl=!aK zGnTAnqfu+D8oQo9@)<?s8cv)T&A4N?Z85Nuy?y?&%urY+LCbdgfk^ylAOgQ*I{hFp z<^N}!IzNt#`brH=#OPv#1U_7N=)u4eEG#oOP@}IB?Q+Mb%FnPsM705j)d{og(t(XO nU0}eNU=RD$N5m#VvKDj7w8**WBOse#J5&4Y5wTaDBdFmI%UpkJ
literal 0 HcmV?d00001
diff --git a/dlls/gdiplus/tests/wine_mac_win.ttx b/dlls/gdiplus/tests/wine_mac_win.ttx new file mode 100644 index 00000000000..c85a8abd50b --- /dev/null +++ b/dlls/gdiplus/tests/wine_mac_win.ttx @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- A font that has an invalid full name on Mac platform and a valid full name on Microsoft platform --> +<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.38"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="uni0000"/> + <GlyphID id="2" name="glyph00002"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.0"/> + <checkSumAdjustment value="0xc8ad052c"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00001011"/> + <unitsPerEm value="2048"/> + <created value="Thu Jan 1 00:00:00 1970"/> + <modified value="Thu Jan 1 00:00:00 1970"/> + <xMin value="68"/> + <yMin value="-63"/> + <xMax value="1405"/> + <yMax value="1575"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="8"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1575"/> + <descent value="-63"/> + <lineGap value="184"/> + <advanceWidthMax value="2048"/> + <minLeftSideBearing value="0"/> + <minRightSideBearing value="0"/> + <xMaxExtent value="1405"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="3"/> + </hhea> + + <maxp> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="0x10000"/> + <numGlyphs value="3"/> + <maxPoints value="8"/> + <maxContours value="2"/> + <maxCompositePoints value="0"/> + <maxCompositeContours value="0"/> + <maxZones value="2"/> + <maxTwilightPoints value="0"/> + <maxStorage value="1"/> + <maxFunctionDefs value="1"/> + <maxInstructionDefs value="0"/> + <maxStackElements value="64"/> + <maxSizeOfInstructions value="46"/> + <maxComponentElements value="0"/> + <maxComponentDepth value="0"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="2"/> + <xAvgCharWidth value="2048"/> + <usWeightClass value="500"/> + <usWidthClass value="5"/> + <fsType value="01111111 11111111"/> + <ySubscriptXSize value="1331"/> + <ySubscriptYSize value="1433"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="286"/> + <ySuperscriptXSize value="1331"/> + <ySuperscriptYSize value="1433"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="983"/> + <yStrikeoutSize value="102"/> + <yStrikeoutPosition value="530"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="2"/> + <bSerifStyle value="0"/> + <bWeight value="6"/> + <bProportion value="3"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="Wine"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="0"/> + <usLastCharIndex value="0"/> + <sTypoAscender value="1638"/> + <sTypoDescender value="-410"/> + <sTypoLineGap value="184"/> + <usWinAscent value="1638"/> + <usWinDescent value="410"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="0"/> + <sCapHeight value="0"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <hmtx> + <mtx name=".notdef" width="2048" lsb="68"/> + <mtx name="glyph00002" width="2048" lsb="0"/> + <mtx name="uni0000" width="2048" lsb="601"/> + </hmtx> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x0" name="uni0000"/><!-- ???? --> + </cmap_format_4> + <cmap_format_0 platformID="1" platEncID="0" language="0"> + <map code="0x0" name="uni0000"/> + <map code="0x8" name="uni0000"/> + <map code="0x9" name="glyph00002"/> + <map code="0xd" name="glyph00002"/> + <map code="0x1d" name="uni0000"/> + </cmap_format_0> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x0" name="uni0000"/><!-- ???? --> + </cmap_format_4> + </cmap> + + <loca> + <!-- The 'loca' table will be calculated by the compiler --> + </loca> + + <glyf> + <TTGlyph name=".notdef"/><!-- contains no outline data --> + <TTGlyph name="glyph00002"/><!-- contains no outline data --> + <TTGlyph name="uni0000"/><!-- contains no outline data --> + </glyf> + + <name> + <namerecord nameID="0" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Copyright (c) 2024 Zhiyi Zhang for CodeWeavers + </namerecord> + <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_mac_win + </namerecord> + <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Regular + </namerecord> + <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_mac_win + </namerecord> + <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True"> + invalid_full_name + </namerecord> + <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Version 1.0 + </namerecord> + <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_mac_win + </namerecord> + <namerecord nameID="0" platformID="3" platEncID="1" langID="0x409"> + Copyright (c) 2024 Zhiyi Zhang for CodeWeavers + </namerecord> + <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409"> + wine_mac_win + </namerecord> + <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409"> + Regular + </namerecord> + <namerecord nameID="3" platformID="3" platEncID="1" langID="0x409"> + wine_mac_win + </namerecord> + <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409"> + wine_mac_win + </namerecord> + <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409"> + Version 1.0 + </namerecord> + <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409"> + wine_mac_win + </namerecord> + </name> + +</ttFont> diff --git a/dlls/gdiplus/tests/wine_unicode_mac.ttf b/dlls/gdiplus/tests/wine_unicode_mac.ttf new file mode 100644 index 0000000000000000000000000000000000000000..4c0af94ade4dd5f9a89246cf5f63ae9320d659c8 GIT binary patch literal 1168 zcmds0O=}ZT6g_W}OroW=bRjN+45HYgq)9BUx+tb@+z1gGT7>a2nU4pVnJ`V-1PW&D zKTyO!poq(E#LuM*7lIo>^cT2LaAiC%GfCrL@P_;Dx#ymH-<wAs1b|Z*A&2GLch>8R zQU4Yo&XK+6gtCjp+*9Tw`VGG`^vKhU4_rjx%J$3d%3b2e^y>i$^IP#9@hAGlAnXlJ z?_!(M0rOHPb|fRsc+aI2%0U-5Q6v6Mw;~z3_LW!cH$JlGHT2o&Prmp~`^@GqER;w9 zN0(lVbo_p`{8h)yN-#3S9`o|}4USViSv_gq#DvMsDBYQITc}J}qXh92h5O^ewZcOd z&!;i>8J@Ai6T&>{{%3kiMJ~4V4AcAL;n?)VBPR123xX%xHg>g&H=lYr(`=H_>N4`M z81wv1y2oQ?;F_M4SePe+h5m-=4QQdZ`CU`y|6iBzeD;z0znPlgT~0FtOE}8-+#H|B z1w6?30?y)DhRum)dY2Wv&F)oT89y>?ph!Wg;ai&V`8iy`f+%JhbHX<eql+ODDEJ7_ z<4&t^u*O(NmA*l=$BLp#WmqDj+JeXKgi%jv!$pfOalkdfJ`Smmh;8&46{n^u8zEH= znymS(b(rb>BX&w=inDCa)|C!XL^h;$C!4D{C*rO(zLaVs?hX^>2R&=mS+nZZ`i8X^ vsG;I2Bj57k#A?KCx8=$MH`zbr+pznQa!A>sbegW;@5p3_B^5_jty299<J*K;
literal 0 HcmV?d00001
diff --git a/dlls/gdiplus/tests/wine_unicode_mac.ttx b/dlls/gdiplus/tests/wine_unicode_mac.ttx new file mode 100644 index 00000000000..377b4b3d4ed --- /dev/null +++ b/dlls/gdiplus/tests/wine_unicode_mac.ttx @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- A font that has an invalid full name on Unicode platform and a valid full name on Mac platform --> +<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="4.38"> + + <GlyphOrder> + <!-- The 'id' attribute is only for humans; it is ignored when parsed. --> + <GlyphID id="0" name=".notdef"/> + <GlyphID id="1" name="uni0000"/> + <GlyphID id="2" name="glyph00002"/> + </GlyphOrder> + + <head> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="1.0"/> + <fontRevision value="1.0"/> + <checkSumAdjustment value="0xc8ad052c"/> + <magicNumber value="0x5f0f3cf5"/> + <flags value="00000000 00001011"/> + <unitsPerEm value="2048"/> + <created value="Thu Jan 1 00:00:00 1970"/> + <modified value="Thu Jan 1 00:00:00 1970"/> + <xMin value="68"/> + <yMin value="-63"/> + <xMax value="1405"/> + <yMax value="1575"/> + <macStyle value="00000000 00000000"/> + <lowestRecPPEM value="8"/> + <fontDirectionHint value="2"/> + <indexToLocFormat value="0"/> + <glyphDataFormat value="0"/> + </head> + + <hhea> + <tableVersion value="0x00010000"/> + <ascent value="1575"/> + <descent value="-63"/> + <lineGap value="184"/> + <advanceWidthMax value="2048"/> + <minLeftSideBearing value="0"/> + <minRightSideBearing value="0"/> + <xMaxExtent value="1405"/> + <caretSlopeRise value="1"/> + <caretSlopeRun value="0"/> + <caretOffset value="0"/> + <reserved0 value="0"/> + <reserved1 value="0"/> + <reserved2 value="0"/> + <reserved3 value="0"/> + <metricDataFormat value="0"/> + <numberOfHMetrics value="3"/> + </hhea> + + <maxp> + <!-- Most of this table will be recalculated by the compiler --> + <tableVersion value="0x10000"/> + <numGlyphs value="3"/> + <maxPoints value="8"/> + <maxContours value="2"/> + <maxCompositePoints value="0"/> + <maxCompositeContours value="0"/> + <maxZones value="2"/> + <maxTwilightPoints value="0"/> + <maxStorage value="1"/> + <maxFunctionDefs value="1"/> + <maxInstructionDefs value="0"/> + <maxStackElements value="64"/> + <maxSizeOfInstructions value="46"/> + <maxComponentElements value="0"/> + <maxComponentDepth value="0"/> + </maxp> + + <OS_2> + <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex' + will be recalculated by the compiler --> + <version value="2"/> + <xAvgCharWidth value="2048"/> + <usWeightClass value="500"/> + <usWidthClass value="5"/> + <fsType value="01111111 11111111"/> + <ySubscriptXSize value="1331"/> + <ySubscriptYSize value="1433"/> + <ySubscriptXOffset value="0"/> + <ySubscriptYOffset value="286"/> + <ySuperscriptXSize value="1331"/> + <ySuperscriptYSize value="1433"/> + <ySuperscriptXOffset value="0"/> + <ySuperscriptYOffset value="983"/> + <yStrikeoutSize value="102"/> + <yStrikeoutPosition value="530"/> + <sFamilyClass value="0"/> + <panose> + <bFamilyType value="2"/> + <bSerifStyle value="0"/> + <bWeight value="6"/> + <bProportion value="3"/> + <bContrast value="0"/> + <bStrokeVariation value="0"/> + <bArmStyle value="0"/> + <bLetterForm value="0"/> + <bMidline value="0"/> + <bXHeight value="0"/> + </panose> + <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/> + <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/> + <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/> + <achVendID value="Wine"/> + <fsSelection value="00000000 01000000"/> + <usFirstCharIndex value="0"/> + <usLastCharIndex value="0"/> + <sTypoAscender value="1638"/> + <sTypoDescender value="-410"/> + <sTypoLineGap value="184"/> + <usWinAscent value="1638"/> + <usWinDescent value="410"/> + <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/> + <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/> + <sxHeight value="0"/> + <sCapHeight value="0"/> + <usDefaultChar value="0"/> + <usBreakChar value="32"/> + <usMaxContext value="1"/> + </OS_2> + + <hmtx> + <mtx name=".notdef" width="2048" lsb="68"/> + <mtx name="glyph00002" width="2048" lsb="0"/> + <mtx name="uni0000" width="2048" lsb="601"/> + </hmtx> + + <cmap> + <tableVersion version="0"/> + <cmap_format_4 platformID="0" platEncID="3" language="0"> + <map code="0x0" name="uni0000"/><!-- ???? --> + </cmap_format_4> + <cmap_format_0 platformID="1" platEncID="0" language="0"> + <map code="0x0" name="uni0000"/> + <map code="0x8" name="uni0000"/> + <map code="0x9" name="glyph00002"/> + <map code="0xd" name="glyph00002"/> + <map code="0x1d" name="uni0000"/> + </cmap_format_0> + <cmap_format_4 platformID="3" platEncID="1" language="0"> + <map code="0x0" name="uni0000"/><!-- ???? --> + </cmap_format_4> + </cmap> + + <loca> + <!-- The 'loca' table will be calculated by the compiler --> + </loca> + + <glyf> + <TTGlyph name=".notdef"/><!-- contains no outline data --> + <TTGlyph name="glyph00002"/><!-- contains no outline data --> + <TTGlyph name="uni0000"/><!-- contains no outline data --> + </glyf> + + <name> + <namerecord nameID="0" platformID="0" platEncID="0" langID="0x0" unicode="True"> + Copyright (c) 2024 Zhiyi Zhang for CodeWeavers + </namerecord> + <namerecord nameID="1" platformID="0" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="2" platformID="0" platEncID="0" langID="0x0" unicode="True"> + Regular + </namerecord> + <namerecord nameID="3" platformID="0" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="4" platformID="0" platEncID="0" langID="0x0" unicode="True"> + invalid_full_name + </namerecord> + <namerecord nameID="5" platformID="0" platEncID="0" langID="0x0" unicode="True"> + Version 1.0 + </namerecord> + <namerecord nameID="6" platformID="0" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="0" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Copyright (c) 2024 Zhiyi Zhang for CodeWeavers + </namerecord> + <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Regular + </namerecord> + <namerecord nameID="3" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + <namerecord nameID="5" platformID="1" platEncID="0" langID="0x0" unicode="True"> + Version 1.0 + </namerecord> + <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True"> + wine_unicode_mac + </namerecord> + </name> + +</ttFont>
From: Zhiyi Zhang zzhang@codeweavers.com
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. --- dlls/gdiplus/font.c | 38 +++++++++++++++++++++++--------------- dlls/gdiplus/tests/font.c | 1 - 2 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index da37279fbef..67d75ed97f6 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -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; @@ -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) diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c index 6a21ea30361..1bbb18f4c6d 100644 --- a/dlls/gdiplus/tests/font.c +++ b/dlls/gdiplus/tests/font.c @@ -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)
This merge request was approved by Esme Povirk.
This merge request was approved by David Kahurani.
Could this be done with .sfd source files instead?
On Thu Apr 4 01:56:29 2024 +0000, Alexandre Julliard wrote:
Could this be done with .sfd source files instead?
I tried .sfd files. I don't think they can specify names with different platform IDs, which is essential to reproduce the bug.
On Thu Apr 4 01:56:29 2024 +0000, Zhiyi Zhang wrote:
I tried .sfd files. I don't think they can specify names with different platform IDs, which is essential to reproduce the bug.
Please change the filenames to be less generic.
Regardless of the bug, there seems to be some code improvements through this MR.
David Kahurani (@ReDress) commented about dlls/gdiplus/tests/font.c:
stat = GdipGetFontCollectionFamilyCount(fonts, &count);
ok(stat == Ok, "GdipGetFontCollectionFamilyCount failed, error %d\n", stat);
ok(count == 1, "Expected count 1, got %d\n", count);
}
else if (i == 1 && stat == FileNotFound)
win_skip("Fonts without Microsoft platform names are unsupported on win7.\n");
else
ok(0, "GdipPrivateAddMemoryFont failed, error %d\n", stat);
stat = GdipDeletePrivateFontCollection(&fonts);
ok(stat == Ok, "GdipDeletePrivateFontCollection failed, error %d\n", stat);
winetest_pop_context();
- }
+}
These tests should either be embedded somewhere or a whole test suite for GdipPrivateAddMemoryFont introduced.
On Thu Apr 4 05:10:24 2024 +0000, David Kahurani wrote:
Please change the filenames to be less generic. Regardless of the bug, there seems to be some code improvements through this MR.
There won't be many fonts there so I think it is unnecessary.
On Thu Apr 4 05:18:55 2024 +0000, David Kahurani wrote:
These tests should either be embedded somewhere or a whole test suite for GdipPrivateAddMemoryFont introduced.
I think having a test_GdipPrivateAddMemoryFont() is already enough.