diff --git a/patches/gdiplus-FontFamily-RefCount/0001-gdiplus-Use-refcounting-for-GpFontFamily-instead-of-.patch b/patches/gdiplus-FontFamily-RefCount/0001-gdiplus-Use-refcounting-for-GpFontFamily-instead-of-.patch new file mode 100644 index 00000000..29a57cdf --- /dev/null +++ b/patches/gdiplus-FontFamily-RefCount/0001-gdiplus-Use-refcounting-for-GpFontFamily-instead-of-.patch @@ -0,0 +1,214 @@ +From 4fc357d3455dd7c75610eda2bf1751f64d55a816 Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 18 Dec 2019 15:14:05 +0800 +Subject: [PATCH] gdiplus: Use refcounting for GpFontFamily instead of cloning. +Content-Type: text/plain; charset=UTF-8 +To: wine-devel@winehq.org + +.Net 4.7+ depends on this behaviour. + +Signed-off-by: Dmitry Timoshkov +--- + dlls/gdiplus/font.c | 38 ++++++++++++----------- + dlls/gdiplus/gdiplus_private.h | 1 + + dlls/gdiplus/tests/font.c | 57 +++++++++++++++++++++++++++++++++- + 3 files changed, 77 insertions(+), 19 deletions(-) + +diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c +index eee272082f..bc4fd2281f 100644 +--- a/dlls/gdiplus/font.c ++++ b/dlls/gdiplus/font.c +@@ -115,8 +115,6 @@ typedef struct + #define MS_OS2_TAG MS_MAKE_TAG('O','S','/','2') + #define MS_HHEA_TAG MS_MAKE_TAG('h','h','e','a') + +-static GpStatus clone_font_family(const GpFontFamily *, GpFontFamily **); +- + static GpFontCollection installedFontCollection = {0}; + + /******************************************************************************* +@@ -183,13 +181,8 @@ GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, + (*font)->unit = unit; + (*font)->emSize = emSize; + (*font)->otm = otm; +- +- stat = clone_font_family(fontFamily, &(*font)->family); +- if (stat != Ok) +- { +- heap_free(*font); +- return stat; +- } ++ (*font)->family = (GpFontFamily *)fontFamily; ++ InterlockedIncrement(&(*font)->family->ref); + + TRACE("<-- %p\n", *font); + +@@ -322,7 +315,10 @@ GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) + if (!(font && family)) + return InvalidParameter; + +- return GdipCloneFontFamily(font->family, family); ++ InterlockedIncrement(&font->family->ref); ++ *family = font->family; ++ ++ return Ok; + } + + static REAL get_font_size(const GpFont *font) +@@ -518,8 +514,6 @@ GpStatus WINGDIPAPI GdipGetLogFontW(GpFont *font, GpGraphics *graphics, LOGFONTW + */ + GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont) + { +- GpStatus stat; +- + TRACE("(%p, %p)\n", font, cloneFont); + + if(!font || !cloneFont) +@@ -529,10 +523,10 @@ GpStatus WINGDIPAPI GdipCloneFont(GpFont *font, GpFont **cloneFont) + if(!*cloneFont) return OutOfMemory; + + **cloneFont = *font; +- stat = GdipCloneFontFamily(font->family, &(*cloneFont)->family); +- if (stat != Ok) heap_free(*cloneFont); ++ InterlockedIncrement(&font->family->ref); ++ (*cloneFont)->family = font->family; + +- return stat; ++ return Ok; + } + + /******************************************************************************* +@@ -769,6 +763,7 @@ GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, + ffamily->descent = fm.descent; + ffamily->line_spacing = fm.line_spacing; + ffamily->dpi = fm.dpi; ++ ffamily->ref = 1; + + *FontFamily = ffamily; + +@@ -783,6 +778,7 @@ static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clo + if (!*clone) return OutOfMemory; + + **clone = *family; ++ (*clone)->ref = 1; + + return Ok; + } +@@ -867,11 +863,17 @@ GpStatus WINGDIPAPI GdipGetFamilyName (GDIPCONST GpFontFamily *family, + */ + GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) + { +- if (!FontFamily) ++ LONG ref; ++ ++ if (!FontFamily || !FontFamily->ref) + return InvalidParameter; +- TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName)); + +- heap_free (FontFamily); ++ ref = InterlockedDecrement(&FontFamily->ref); ++ if (!ref) ++ { ++ TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName)); ++ heap_free(FontFamily); ++ } + + return Ok; + } +diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h +index 8c4fcceded..6b48c360e6 100644 +--- a/dlls/gdiplus/gdiplus_private.h ++++ b/dlls/gdiplus/gdiplus_private.h +@@ -518,6 +518,7 @@ struct GpFontCollection{ + }; + + struct GpFontFamily{ ++ LONG ref; + WCHAR FamilyName[LF_FACESIZE]; + UINT16 em_height, ascent, descent, line_spacing; /* in font units */ + int dpi; +diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c +index 33b75c5bc5..3cada58e39 100644 +--- a/dlls/gdiplus/tests/font.c ++++ b/dlls/gdiplus/tests/font.c +@@ -141,7 +141,6 @@ static void test_createfont(void) + expect(Ok, stat); + stat = GdipGetFamilyName(fontfamily2, familyname, 0); + expect(Ok, stat); +-todo_wine + ok (fontfamily == fontfamily2, "Unexpected family instance.\n"); + ok (lstrcmpiW(Tahoma, familyname) == 0, "Expected Tahoma, got %s\n", + wine_dbgstr_w(familyname)); +@@ -1282,6 +1281,61 @@ static void test_GdipGetFontCollectionFamilyCount(void) + ok(status == InvalidParameter, "Unexpected status %d.\n", status); + } + ++static void test_CloneFont(void) ++{ ++ GpStatus status; ++ GpFont *font, *font2; ++ GpFontFamily *family, *family2; ++ REAL height; ++ Unit unit; ++ int style; ++ ++ status = GdipCreateFontFamilyFromName(Tahoma, NULL, &family); ++ expect(Ok, status); ++ ++ status = GdipCreateFont(family, 30.0f, FontStyleRegular, UnitPixel, &font); ++ expect(Ok, status); ++ ++ status = GdipGetFontUnit(font, &unit); ++ expect(Ok, status); ++ ok(unit == UnitPixel, "got %u\n", unit); ++ ++ status = GdipGetFontSize(font, &height); ++ expect(Ok, status); ++ ok(height == 30.0f, "got %f\n", height); ++ ++ status = GdipGetFontStyle(font, &style); ++ expect(Ok, status); ++ ok(style == FontStyleRegular, "got %d\n", style); ++ ++ status = GdipGetFamily(font, &family2); ++ expect(Ok, status); ++ ok(family == family2, "got %p\n", family2); ++ ++ status = GdipCloneFont(font, &font2); ++ expect(Ok, status); ++ ++ status = GdipGetFontUnit(font2, &unit); ++ expect(Ok, status); ++ ok(unit == UnitPixel, "got %u\n", unit); ++ ++ status = GdipGetFontSize(font2, &height); ++ expect(Ok, status); ++ ok(height == 30.0f, "got %f\n", height); ++ ++ status = GdipGetFontStyle(font2, &style); ++ expect(Ok, status); ++ ok(style == FontStyleRegular, "got %d\n", style); ++ ++ status = GdipGetFamily(font2, &family2); ++ expect(Ok, status); ++ ok(family == family2, "got %p\n", family2); ++ ++ GdipDeleteFont(font2); ++ GdipDeleteFont(font); ++ GdipDeleteFontFamily(family); ++} ++ + START_TEST(font) + { + struct GdiplusStartupInput gdiplusStartupInput; +@@ -1301,6 +1355,7 @@ START_TEST(font) + + GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); + ++ test_CloneFont(); + test_long_name(); + test_font_transform(); + test_font_substitution(); +-- +2.20.1 + diff --git a/patches/gdiplus-FontFamily-RefCount/definition b/patches/gdiplus-FontFamily-RefCount/definition new file mode 100644 index 00000000..93226013 --- /dev/null +++ b/patches/gdiplus-FontFamily-RefCount/definition @@ -0,0 +1 @@ +Fixes: [48489] gdiplus: Reference cound the GpFontFamily object. diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index f87858b7..ccd8d01f 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -150,6 +150,7 @@ patch_enable_all () enable_fsutil_Stub_Program="$1" enable_gdi32_Lazy_Font_Initialization="$1" enable_gdi32_rotation="$1" + enable_gdiplus_FontFamily_RefCount="$1" enable_gdiplus_GdipCreateBitmapFromHBITMAP="$1" enable_gdiplus_Performance_Improvements="$1" enable_imagehlp_BindImageEx="$1" @@ -583,6 +584,9 @@ patch_enable () gdi32-rotation) enable_gdi32_rotation="$2" ;; + gdiplus-FontFamily-RefCount) + enable_gdiplus_FontFamily_RefCount="$2" + ;; gdiplus-GdipCreateBitmapFromHBITMAP) enable_gdiplus_GdipCreateBitmapFromHBITMAP="$2" ;; @@ -1453,7 +1457,7 @@ fi # subdirectory of a git tree, which has the effect that no patches # are applied, but the exitcode is zero. To avoid broken builds we # will workaround this issue or abort. -test ! -d ".git" && git rev-parse --git-dir >/dev/null 2>&1 +test ! -e ".git" && git rev-parse --git-dir >/dev/null 2>&1 workaround_git_bug="$?" # Apply the patches using gitapply.sh, a small wrapper around 'patch' @@ -4150,6 +4154,21 @@ if test "$enable_gdi32_rotation" -eq 1; then ) >> "$patchlist" fi +# Patchset gdiplus-FontFamily-RefCount +# | +# | This patchset fixes the following Wine bugs: +# | * [#48489] gdiplus: Reference cound the GpFontFamily object. +# | +# | Modified files: +# | * dlls/gdiplus/font.c, dlls/gdiplus/gdiplus_private.h, dlls/gdiplus/tests/font.c +# | +if test "$enable_gdiplus_FontFamily_RefCount" -eq 1; then + patch_apply gdiplus-FontFamily-RefCount/0001-gdiplus-Use-refcounting-for-GpFontFamily-instead-of-.patch + ( + printf '%s\n' '+ { "Dmitry Timoshkov", "gdiplus: Use refcounting for GpFontFamily instead of cloning.", 1 },'; + ) >> "$patchlist" +fi + # Patchset gdiplus-GdipCreateBitmapFromHBITMAP # | # | This patchset fixes the following Wine bugs: