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.
This commit is contained in:
Artur Wieczorek
2020-04-05 20:57:56 +02:00
parent 43b3a3fc5b
commit f0e458e25c

View File

@@ -361,6 +361,14 @@ public:
virtual Brush* GetGDIPlusBrush() { return m_textBrush; } virtual Brush* GetGDIPlusBrush() { return m_textBrush; }
virtual Font* GetGDIPlusFont() { return m_font; } 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 : private :
// Common part of all ctors, flags here is a combination of values of // Common part of all ctors, flags here is a combination of values of
@@ -381,6 +389,9 @@ private :
Brush* m_textBrush; Brush* m_textBrush;
Font* m_font; Font* m_font;
#if wxUSE_PRIVATE_FONTS
FontFamily* m_privateFontFamily;
#endif // wxUSE_PRIVATE_FONTS
}; };
class wxGDIPlusContext : public wxGraphicsContext 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 // If the user has registered any private fonts, they should be used in
// preference to any system-wide ones. // preference to any system-wide ones.
m_font = NULL; m_font = NULL;
m_privateFontFamily = NULL;
if ( gs_privateFonts ) if ( gs_privateFonts )
{ {
const int count = gs_privateFonts->GetFamilyCount(); const int count = gs_privateFonts->GetFamilyCount();
@@ -1100,7 +1112,12 @@ wxGDIPlusFontData::Init(const wxString& name,
int rc = gs_pFontFamily[j].GetFamilyName(familyName); int rc = gs_pFontFamily[j].GetFamilyName(familyName);
if ( rc == 0 && name == 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; break;
} }
} }
@@ -2228,17 +2245,33 @@ void wxGDIPlusContext::GetTextExtent( const wxString &str, wxDouble *width, wxDo
// Get the font metrics if we actually need them. // Get the font metrics if we actually need them.
if ( descent || externalLeading || (height && str.empty()) ) if ( descent || externalLeading || (height && str.empty()) )
{ {
FontFamily ffamily ; // Because it looks that calling to Font::GetFamily() for a private font is
f->GetFamily(&ffamily) ; // 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 // Notice that we must use the real font style or the results would be
// incorrect for italic/bold fonts. // incorrect for italic/bold fonts.
const INT style = f->GetStyle(); const INT style = f->GetStyle();
const REAL size = f->GetSize(); const REAL size = f->GetSize();
const REAL emHeight = ffamily.GetEmHeight(style); const REAL emHeight = pffamily->GetEmHeight(style);
REAL rDescent = ffamily.GetCellDescent(style) * size / emHeight; REAL rDescent = pffamily->GetCellDescent(style) * size / emHeight;
REAL rAscent = ffamily.GetCellAscent(style) * size / emHeight; REAL rAscent = pffamily->GetCellAscent(style) * size / emHeight;
REAL rHeight = ffamily.GetLineSpacing(style) * size / emHeight; REAL rHeight = pffamily->GetLineSpacing(style) * size / emHeight;
if ( !pPrivFontFamily )
delete pffamily;
if ( height && str.empty() ) if ( height && str.empty() )
*height = rHeight; *height = rHeight;