From a5540798605b3ef9abcf654bc28d9dd8d8736e53 Mon Sep 17 00:00:00 2001 From: Esme Povirk Date: Wed, 26 May 2021 15:49:18 -0500 Subject: [PATCH] gdiplus: Implement reference counting for private font families. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50896 Signed-off-by: Esme Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/font.c | 22 ++++++++++++++++------ dlls/gdiplus/gdiplus_private.h | 2 ++ dlls/gdiplus/tests/font.c | 13 ++++++++++++- 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index cf43985d02a..64604367da3 100644 --- a/dlls/gdiplus/font.c +++ b/dlls/gdiplus/font.c @@ -190,7 +190,7 @@ GpStatus WINGDIPAPI GdipCreateFont(GDIPCONST GpFontFamily *fontFamily, (*font)->unit = unit; (*font)->emSize = emSize; (*font)->otm = otm; - (*font)->family = (GpFontFamily *)fontFamily; + GdipCloneFontFamily((GpFontFamily*)fontFamily, &(*font)->family); TRACE("<-- %p\n", *font); @@ -323,8 +323,7 @@ GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) if (!(font && family)) return InvalidParameter; - *family = font->family; - return Ok; + return GdipCloneFontFamily(font->family, family); } static REAL get_font_size(const GpFont *font) @@ -746,9 +745,8 @@ GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, { if (!wcsicmp(lf.lfFaceName, collection->FontFamilies[i]->FamilyName)) { - *family = collection->FontFamilies[i]; + status = GdipCloneFontFamily(collection->FontFamilies[i], family); TRACE("<-- %p\n", *family); - status = Ok; break; } } @@ -778,6 +776,10 @@ GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily *family, GpFontFamily **clo TRACE("%p (%s), %p\n", family, debugstr_w(family->FamilyName), clone); *clone = family; + + if (!family->installed) + InterlockedIncrement(&family->ref); + return Ok; } @@ -835,6 +837,11 @@ GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) if (!FontFamily) return InvalidParameter; + if (!FontFamily->installed && !InterlockedDecrement(&FontFamily->ref)) + { + heap_free(FontFamily); + } + return Ok; } @@ -1079,7 +1086,7 @@ GpStatus WINGDIPAPI GdipDeletePrivateFontCollection(GpFontCollection **fontColle if (!fontCollection) return InvalidParameter; - for (i = 0; i < (*fontCollection)->count; i++) heap_free((*fontCollection)->FontFamilies[i]); + for (i = 0; i < (*fontCollection)->count; i++) GdipDeleteFontFamily((*fontCollection)->FontFamilies[i]); heap_free((*fontCollection)->FontFamilies); heap_free(*fontCollection); @@ -1541,6 +1548,7 @@ GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( for (i = 0; i < numSought && i < fontCollection->count; i++) { + /* caller is responsible for cloning these if it keeps references */ gpfamilies[i] = fontCollection->FontFamilies[i]; } @@ -1641,6 +1649,8 @@ static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, family->descent = fm.descent; family->line_spacing = fm.line_spacing; family->dpi = fm.dpi; + family->installed = param->is_system; + family->ref = 1; lstrcpyW(family->FamilyName, lfw->lfFaceName); diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 2b0f920473d..22213e9f278 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -543,6 +543,8 @@ struct GpFontFamily{ WCHAR FamilyName[LF_FACESIZE]; UINT16 em_height, ascent, descent, line_spacing; /* in font units */ int dpi; + BOOL installed; + LONG ref; }; /* internal use */ diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c index 32cd1ff2c4f..b208989c054 100644 --- a/dlls/gdiplus/tests/font.c +++ b/dlls/gdiplus/tests/font.c @@ -72,7 +72,7 @@ static void test_long_name(void) GpStatus stat; GpFontCollection *fonts; INT num_families; - GpFontFamily *family; + GpFontFamily *family, *cloned_family; WCHAR family_name[LF_FACESIZE]; GpFont *font; @@ -98,6 +98,10 @@ static void test_long_name(void) stat = GdipCreateFont(family, 256.0, FontStyleRegular, UnitPixel, &font); ok(stat == Ok, "GdipCreateFont failed: %d\n", stat); + stat = GdipCloneFontFamily(family, &cloned_family); + ok(stat == Ok, "GdipCloneFontFamily failed: %d\n", stat); + ok(family == cloned_family, "GdipCloneFontFamily returned new object\n"); + /* Cleanup */ stat = GdipDeleteFont(font); @@ -106,6 +110,13 @@ static void test_long_name(void) stat = GdipDeletePrivateFontCollection(&fonts); ok(stat == Ok, "GdipDeletePrivateFontCollection failed: %d\n", stat); + /* Cloned family survives after collection is deleted */ + stat = GdipGetFamilyName(cloned_family, family_name, LANG_NEUTRAL); + ok(stat == Ok, "GdipGetFamilyName failed: %d\n", stat); + + stat = GdipDeleteFontFamily(cloned_family); + ok(stat == Ok, "GdipDeleteFontFamily failed: %d\n", stat); + DELETE_FONTFILE(path); }