From b9307cfa61e9884b01d34c2310ec1ffbb1868728 Mon Sep 17 00:00:00 2001 From: Dmitry Timoshkov Date: Fri, 31 Jan 2020 16:47:24 +0800 Subject: [PATCH] gdiplus: Create FontFamily objects only once for the FontCollection. .Net 4.7+ depends on this behaviour and expects to be able to do pointer equality tests for FontFamily objects. Signed-off-by: Dmitry Timoshkov Signed-off-by: Vincent Povirk Signed-off-by: Alexandre Julliard --- dlls/gdiplus/font.c | 208 ++++++++++++++++---------------------- dlls/gdiplus/tests/font.c | 6 -- 2 files changed, 89 insertions(+), 125 deletions(-) diff --git a/dlls/gdiplus/font.c b/dlls/gdiplus/font.c index eee272082f1..a7719a94583 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,7 @@ 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; TRACE("<-- %p\n", *font); @@ -322,7 +314,8 @@ GpStatus WINGDIPAPI GdipGetFamily(GpFont *font, GpFontFamily **family) if (!(font && family)) return InvalidParameter; - return GdipCloneFontFamily(font->family, family); + *family = font->family; + return Ok; } static REAL get_font_size(const GpFont *font) @@ -518,8 +511,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 +520,7 @@ 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); - - return stat; + return Ok; } /******************************************************************************* @@ -699,29 +687,6 @@ static BOOL get_font_metrics(HDC hdc, struct font_metrics *fm) return TRUE; } -static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) -{ - LOGFONTW lf; - HDC hdc = CreateCompatibleDC(0); - GpStatus ret = FontFamilyNotFound; - - if(!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) - { - HFONT hfont, old_font; - - lstrcpyW(fm->facename, lf.lfFaceName); - - hfont = CreateFontIndirectW(&lf); - old_font = SelectObject(hdc, hfont); - ret = get_font_metrics(hdc, fm) ? Ok : NotTrueTypeFont; - SelectObject(hdc, old_font); - DeleteObject(hfont); - } - - DeleteDC(hdc); - return ret; -} - /******************************************************************************* * GdipCreateFontFamilyFromName [GDIPLUS.@] * @@ -743,48 +708,45 @@ static GpStatus find_installed_font(const WCHAR *name, struct font_metrics *fm) */ GpStatus WINGDIPAPI GdipCreateFontFamilyFromName(GDIPCONST WCHAR *name, - GpFontCollection *fontCollection, - GpFontFamily **FontFamily) + GpFontCollection *collection, + GpFontFamily **family) { - GpStatus stat; - GpFontFamily* ffamily; - struct font_metrics fm; + HDC hdc; + LOGFONTW lf; + GpStatus status; + int i; - TRACE("%s, %p %p\n", debugstr_w(name), fontCollection, FontFamily); + TRACE("%s, %p %p\n", debugstr_w(name), collection, family); - if (!(name && FontFamily)) + if (!name || !family) return InvalidParameter; - if (fontCollection) - FIXME("No support for FontCollections yet!\n"); - stat = find_installed_font(name, &fm); - if (stat != Ok) return stat; + if (!collection) + { + status = GdipNewInstalledFontCollection(&collection); + if (status != Ok) return status; + } - ffamily = heap_alloc_zero(sizeof (GpFontFamily)); - if (!ffamily) return OutOfMemory; + status = FontFamilyNotFound; - lstrcpyW(ffamily->FamilyName, fm.facename); - ffamily->em_height = fm.em_height; - ffamily->ascent = fm.ascent; - ffamily->descent = fm.descent; - ffamily->line_spacing = fm.line_spacing; - ffamily->dpi = fm.dpi; + hdc = CreateCompatibleDC(0); - *FontFamily = ffamily; + if (!EnumFontFamiliesW(hdc, name, is_font_installed_proc, (LPARAM)&lf)) + { + for (i = 0; i < collection->count; i++) + { + if (!wcsicmp(lf.lfFaceName, collection->FontFamilies[i]->FamilyName)) + { + *family = collection->FontFamilies[i]; + TRACE("<-- %p\n", *family); + status = Ok; + break; + } + } + } - TRACE("<-- %p\n", ffamily); - - return Ok; -} - -static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clone) -{ - *clone = heap_alloc_zero(sizeof(GpFontFamily)); - if (!*clone) return OutOfMemory; - - **clone = *family; - - return Ok; + DeleteDC(hdc); + return status; } /******************************************************************************* @@ -799,20 +761,14 @@ static GpStatus clone_font_family(const GpFontFamily *family, GpFontFamily **clo * RETURNS * SUCCESS: Ok */ -GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily* FontFamily, GpFontFamily** clonedFontFamily) +GpStatus WINGDIPAPI GdipCloneFontFamily(GpFontFamily *family, GpFontFamily **clone) { - GpStatus status; + if (!family || !clone) + return InvalidParameter; - if (!(FontFamily && clonedFontFamily)) return InvalidParameter; - - TRACE("%p (%s), %p\n", FontFamily, - debugstr_w(FontFamily->FamilyName), clonedFontFamily); - - status = clone_font_family(FontFamily, clonedFontFamily); - if (status != Ok) return status; - - TRACE("<-- %p\n", *clonedFontFamily); + TRACE("%p (%s), %p\n", family, debugstr_w(family->FamilyName), clone); + *clone = family; return Ok; } @@ -869,9 +825,6 @@ GpStatus WINGDIPAPI GdipDeleteFontFamily(GpFontFamily *FontFamily) { if (!FontFamily) return InvalidParameter; - TRACE("Deleting %p (%s)\n", FontFamily, debugstr_w(FontFamily->FamilyName)); - - heap_free (FontFamily); return Ok; } @@ -1498,6 +1451,7 @@ struct add_font_param GpFontCollection *collection; BOOL is_system; GpStatus stat; + HDC hdc; }; static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, DWORD type, LPARAM lParam); @@ -1528,10 +1482,9 @@ GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, else { struct add_font_param param; - HDC hdc; LOGFONTW lfw; - hdc = CreateCompatibleDC(0); + param.hdc = CreateCompatibleDC(0); /* Truncate name if necessary, GDI32 can't deal with long names */ if(lstrlenW(name) > LF_FACESIZE - 1) @@ -1543,10 +1496,10 @@ GpStatus WINGDIPAPI GdipPrivateAddMemoryFont(GpFontCollection* fontCollection, param.collection = fontCollection; param.is_system = FALSE; - if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) + if (!EnumFontFamiliesExW(param.hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) ret = param.stat; - DeleteDC(hdc); + DeleteDC(param.hdc); } heap_free(name); return ret; @@ -1575,7 +1528,6 @@ GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( GpFontFamily* gpfamilies[], INT* numFound) { INT i; - GpStatus stat=Ok; TRACE("%p, %d, %p, %p\n", fontCollection, numSought, gpfamilies, numFound); @@ -1584,31 +1536,24 @@ GpStatus WINGDIPAPI GdipGetFontCollectionFamilyList( memset(gpfamilies, 0, sizeof(*gpfamilies) * numSought); - for (i = 0; i < numSought && i < fontCollection->count && stat == Ok; i++) + for (i = 0; i < numSought && i < fontCollection->count; i++) { - stat = GdipCloneFontFamily(fontCollection->FontFamilies[i], &gpfamilies[i]); + gpfamilies[i] = fontCollection->FontFamilies[i]; } - if (stat == Ok) - *numFound = i; - else - { - int numToFree=i; - for (i=0; icollection; - GpFontFamily* family; - GpStatus stat; + GpFontFamily *family; + HFONT hfont, old_hfont; + struct font_metrics fm; int i; param->stat = Ok; @@ -1651,25 +1597,50 @@ static INT CALLBACK add_font_proc(const LOGFONTW *lfw, const TEXTMETRICW *ntm, fonts->allocated = new_alloc_count; } - if ((stat = GdipCreateFontFamilyFromName(lfw->lfFaceName, NULL, &family)) != Ok) + family = heap_alloc(sizeof(*family)); + if (!family) { - WARN("Failed to create font family for %s, status %d.\n", debugstr_w(lfw->lfFaceName), stat); if (param->is_system) return 1; - param->stat = stat; + + param->stat = OutOfMemory; return 0; } /* skip duplicates */ for (i=0; icount; i++) { - if (wcsicmp(family->FamilyName, fonts->FontFamilies[i]->FamilyName) == 0) + if (wcsicmp(lfw->lfFaceName, fonts->FontFamilies[i]->FamilyName) == 0) { - GdipDeleteFontFamily(family); + heap_free(family); return 1; } } + hfont = CreateFontIndirectW(lfw); + old_hfont = SelectObject(param->hdc, hfont); + + if (!get_font_metrics(param->hdc, &fm)) + { + SelectObject(param->hdc, old_hfont); + DeleteObject(hfont); + + heap_free(family); + param->stat = OutOfMemory; + return 0; + } + + SelectObject(param->hdc, old_hfont); + DeleteObject(hfont); + + family->em_height = fm.em_height; + family->ascent = fm.ascent; + family->descent = fm.descent; + family->line_spacing = fm.line_spacing; + family->dpi = fm.dpi; + + lstrcpyW(family->FamilyName, lfw->lfFaceName); + fonts->FontFamilies[fonts->count++] = family; return 1; @@ -1686,10 +1657,9 @@ GpStatus WINGDIPAPI GdipNewInstalledFontCollection( if (installedFontCollection.count == 0) { struct add_font_param param; - HDC hdc; LOGFONTW lfw; - hdc = CreateCompatibleDC(0); + param.hdc = CreateCompatibleDC(0); lfw.lfCharSet = DEFAULT_CHARSET; lfw.lfFaceName[0] = 0; @@ -1697,14 +1667,14 @@ GpStatus WINGDIPAPI GdipNewInstalledFontCollection( param.collection = &installedFontCollection; param.is_system = TRUE; - if (!EnumFontFamiliesExW(hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) + if (!EnumFontFamiliesExW(param.hdc, &lfw, add_font_proc, (LPARAM)¶m, 0)) { free_installed_fonts(); - DeleteDC(hdc); + DeleteDC(param.hdc); return param.stat; } - DeleteDC(hdc); + DeleteDC(param.hdc); } *fontCollection = &installedFontCollection; diff --git a/dlls/gdiplus/tests/font.c b/dlls/gdiplus/tests/font.c index 36079fa7adc..9abb80faaf5 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)); @@ -345,7 +344,6 @@ static void test_fontfamily (void) ZeroMemory (itsName, sizeof(itsName)); stat = GdipCloneFontFamily(family, &clonedFontFamily); expect (Ok, stat); -todo_wine ok (family == clonedFontFamily, "Unexpected family instance.\n"); GdipDeleteFontFamily(family); stat = GdipGetFamilyName(clonedFontFamily, itsName, LANG_NEUTRAL); @@ -1238,7 +1236,6 @@ static void test_GdipGetFontCollectionFamilyList(void) status = GdipGetFontCollectionFamilyList(collection, 1, &family2, &found); ok(status == Ok, "Failed to get family list, status %d.\n", status); ok(found == 1, "Unexpected list count %d.\n", found); -todo_wine ok(family2 == family, "Unexpected family instance.\n"); status = GdipDeleteFontFamily(family); @@ -1338,7 +1335,6 @@ static void test_CloneFont(void) expect(Ok, status); ret = is_family_in_collection(collection, family); -todo_wine ok(ret, "family is not in collection\n"); status = GdipCreateFont(family, 30.0f, FontStyleRegular, UnitPixel, &font); @@ -1358,7 +1354,6 @@ todo_wine status = GdipGetFamily(font, &family2); expect(Ok, status); -todo_wine ok(family == family2, "got %p\n", family2); status = GdipCloneFont(font, &font2); @@ -1378,7 +1373,6 @@ todo_wine status = GdipGetFamily(font2, &family2); expect(Ok, status); -todo_wine ok(family == family2, "got %p\n", family2); GdipDeleteFont(font2);