From f0e458e25cdb5e2ef32fb5b37df414e6cb660c0f Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 5 Apr 2020 20:57:56 +0200 Subject: [PATCH] Get font family of private GDI+ font from the cache When font family of a private font is retrieved with call to Gdiplus::Font::GetFamily() then later on there is thrown access violation exception when array of cached private font families (filled in by Gdiplus::PrivateFontCollection::GetFamilies()) is deleted in wxGDIPlusRenderer::Unload(). Call to Font::GetFamily() is done in wxGDIPlusContext::GetTextExtent() so this issue can be seen once text extent is retrieved for a private font. Because it looks that calling to Font::GetFamily() for a private font is messing up something in the array of cached private font families so we should avoid calling this method and directly fetch corresponding font family from the cache instead. Reference to the cached font family would be stored in the wxGDIPlusDataFont and it could be fetched from there directly instead of making a call to Font::GetFamily(). Closes #18704. --- src/msw/graphics.cpp | 47 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/msw/graphics.cpp b/src/msw/graphics.cpp index 4261cebf3f..73676ce6e2 100644 --- a/src/msw/graphics.cpp +++ b/src/msw/graphics.cpp @@ -361,6 +361,14 @@ public: virtual Brush* GetGDIPlusBrush() { return m_textBrush; } virtual Font* GetGDIPlusFont() { return m_font; } + virtual FontFamily * GetGDIPlusPrivateFontFamily() const + { +#if wxUSE_PRIVATE_FONTS + return m_privateFontFamily; +#else + return NULL; +#endif // wxUSE_PRIVATE_FONTS + } private : // Common part of all ctors, flags here is a combination of values of @@ -381,6 +389,9 @@ private : Brush* m_textBrush; Font* m_font; +#if wxUSE_PRIVATE_FONTS + FontFamily* m_privateFontFamily; +#endif // wxUSE_PRIVATE_FONTS }; class wxGDIPlusContext : public wxGraphicsContext @@ -1086,6 +1097,7 @@ wxGDIPlusFontData::Init(const wxString& name, // If the user has registered any private fonts, they should be used in // preference to any system-wide ones. m_font = NULL; + m_privateFontFamily = NULL; if ( gs_privateFonts ) { const int count = gs_privateFonts->GetFamilyCount(); @@ -1100,7 +1112,12 @@ wxGDIPlusFontData::Init(const wxString& name, int rc = gs_pFontFamily[j].GetFamilyName(familyName); if ( rc == 0 && name == familyName ) { - m_font = new Font(&gs_pFontFamily[j], sizeInPixels, style, UnitPixel); + // Store reference to the cached FontFamily to avoid calling Font::GetFamily() + // for private font because calling this method apparently is messing up something + // in the array of font families (m_privateFontFamily). + m_privateFontFamily = &gs_pFontFamily[j]; + m_font = new Font(m_privateFontFamily, sizeInPixels, style, UnitPixel); + break; } } @@ -2228,17 +2245,33 @@ void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDo // Get the font metrics if we actually need them. if ( descent || externalLeading || (height && str.empty()) ) { - FontFamily ffamily ; - f->GetFamily(&ffamily) ; + // Because it looks that calling to Font::GetFamily() for a private font is + // messing up something in the array of cached private font families so + // we should avoid calling this method fetch corresponding font family + // from the cache instead. + FontFamily* pPrivFontFamily = ((wxGDIPlusFontData*)m_font.GetRefData())->GetGDIPlusPrivateFontFamily(); + FontFamily* pffamily; + if ( pPrivFontFamily ) + { + pffamily = pPrivFontFamily; + } + else + { + pffamily = new FontFamily; + f->GetFamily(pffamily); + } // Notice that we must use the real font style or the results would be // incorrect for italic/bold fonts. const INT style = f->GetStyle(); const REAL size = f->GetSize(); - const REAL emHeight = ffamily.GetEmHeight(style); - REAL rDescent = ffamily.GetCellDescent(style) * size / emHeight; - REAL rAscent = ffamily.GetCellAscent(style) * size / emHeight; - REAL rHeight = ffamily.GetLineSpacing(style) * size / emHeight; + const REAL emHeight = pffamily->GetEmHeight(style); + REAL rDescent = pffamily->GetCellDescent(style) * size / emHeight; + REAL rAscent = pffamily->GetCellAscent(style) * size / emHeight; + REAL rHeight = pffamily->GetLineSpacing(style) * size / emHeight; + + if ( !pPrivFontFamily ) + delete pffamily; if ( height && str.empty() ) *height = rHeight;