Related: tdf#132536 drop FreetypeManager FreetypeFont caching

the FreetypeFont only makes sense in the context of the FreetypeFontInstance it
belongs to so remove the faux "garbage collection" and just have FreetypeFontInstance
own the FreetypeFont and keep it simple.

Setting a value low enough to make the garbage collection kick in just crasheed
libreoffice by pulling FreetypeFont out from under living FreetypeFontInstance
seeing as the Cache/Uncache was by the FreeTypeTextRenderImpl not the
FreetypeFontInstance which had HarfBuff faces which continued to point to the
removed FreetypeFont

There is still a cache at the LogicalFontInstance level, so this aligns the
libfreetype platforms with windows, mac etc.

Change-Id: Iac669fae8dc1df81a5bc10d2943d84a2ff623180
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/94546
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/compilerplugins/clang/unusedmethods.results b/compilerplugins/clang/unusedmethods.results
index a17231a..a3bdde1 100644
--- a/compilerplugins/clang/unusedmethods.results
+++ b/compilerplugins/clang/unusedmethods.results
@@ -1768,8 +1768,6 @@ vcl/inc/skia/utils.hxx:62
    void SkiaHelper::dump(const class SkBitmap &,const char *)
vcl/inc/skia/zone.hxx:22
    void SkiaZone::relaxWatchdogTimings()
vcl/inc/unx/glyphcache.hxx:108
    void FreetypeManager::ClearFontOptions()
vcl/inc/unx/gtk/gtkframe.hxx:217
    void ensure_dbus_setup(struct _GdkWindow *,class GtkSalFrame *)
vcl/inc/unx/saldisp.hxx:377
diff --git a/vcl/inc/unx/freetype_glyphcache.hxx b/vcl/inc/unx/freetype_glyphcache.hxx
index 29554b6..c375ba2 100644
--- a/vcl/inc/unx/freetype_glyphcache.hxx
+++ b/vcl/inc/unx/freetype_glyphcache.hxx
@@ -106,7 +106,7 @@ class SAL_DLLPUBLIC_RTTI FreetypeFontInstance : public LogicalFontInstance
{
    friend rtl::Reference<LogicalFontInstance> FreetypeFontFace::CreateFontInstance(const FontSelectPattern&) const;

    FreetypeFont* mpFreetypeFont;
    std::unique_ptr<FreetypeFont> mxFreetypeFont;

    virtual hb_font_t* ImplInitHbFont() override;
    virtual bool ImplGetGlyphBoundRect(sal_GlyphId, tools::Rectangle&, bool) const override;
@@ -117,8 +117,7 @@ protected:
public:
    virtual ~FreetypeFontInstance() override;

    void SetFreetypeFont(FreetypeFont* p);
    FreetypeFont* GetFreetypeFont() const { return mpFreetypeFont; }
    FreetypeFont& GetFreetypeFont() const { return *mxFreetypeFont; }

    virtual bool GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const override;
};
diff --git a/vcl/inc/unx/freetypetextrender.hxx b/vcl/inc/unx/freetypetextrender.hxx
index 4c15fb9..ccc1db0 100644
--- a/vcl/inc/unx/freetypetextrender.hxx
+++ b/vcl/inc/unx/freetypetextrender.hxx
@@ -22,14 +22,15 @@

#include <textrender.hxx>

class FreetypeFont;
class FreetypeFontInstance;

// Generic implementation that uses freetype, but DrawTextLayout()
// still needs implementing (e.g. by Cairo or Skia).
class VCL_DLLPUBLIC FreeTypeTextRenderImpl : public TextRenderImpl
{
protected:
    FreetypeFont*   mpFreetypeFont[ MAX_FALLBACK ];
    rtl::Reference<FreetypeFontInstance>
                            mpFreetypeFont[ MAX_FALLBACK ];

    Color           mnTextColor;

diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h
index 6e68c96..b696618 100644
--- a/vcl/inc/unx/genpspgraphics.h
+++ b/vcl/inc/unx/genpspgraphics.h
@@ -32,7 +32,7 @@ class PhysicalFontCollection;

namespace psp { struct JobData; class PrinterGfx; }

class FreetypeFont;
class FreetypeFontInstance;
class FontAttributes;
class SalInfoPrinter;
class ImplFontMetricData;
@@ -42,7 +42,8 @@ class VCL_DLLPUBLIC GenPspGraphics final : public SalGraphics
    psp::JobData*           m_pJobData;
    psp::PrinterGfx*        m_pPrinterGfx;

    FreetypeFont*           m_pFreetypeFont[ MAX_FALLBACK ];
    rtl::Reference<FreetypeFontInstance>
                            m_pFreetypeFont[ MAX_FALLBACK ];
public:
                            GenPspGraphics();
    virtual                ~GenPspGraphics() override;
diff --git a/vcl/inc/unx/glyphcache.hxx b/vcl/inc/unx/glyphcache.hxx
index 38c51a0..983a6ec 100644
--- a/vcl/inc/unx/glyphcache.hxx
+++ b/vcl/inc/unx/glyphcache.hxx
@@ -52,7 +52,7 @@ namespace vcl { struct FontCapabilities; }
 /**
  * The FreetypeManager caches various aspects of Freetype fonts
  *
  * It mainly consists of three std::unordered_map lists, which hold the items of the cache.
  * It mainly consists of two std::unordered_map lists, which hold the items of the cache.
  *
  * They form kind of a tree, with FreetypeFontFile as the roots, referenced by multiple FreetypeFontInfo
  * entries, which are referenced by the FreetypeFont items.
@@ -63,17 +63,13 @@ namespace vcl { struct FontCapabilities; }
  * The respective resources are:
  *   FreetypeFontFile = holds the mmapped font file, as long as it's used by any FreetypeFontInfo.
  *   FreetypeFontInfo = holds the FT_FaceRec_ object, as long as it's used by any FreetypeFont.
  *   FreetypeFont     = holds the FT_SizeRec_.
  *   FreetypeFont     = holds the FT_SizeRec_ and is owned by a FreetypeFontInstance
  *
  * FreetypeFontInfo therefore is embedded in the Freetype subclass of PhysicalFontFace.
  * FreetypeFont is embedded in the Freetype subclass of LogicalFontInstance.
  * FreetypeFont is owned by FreetypeFontInstance, the Freetype subclass of LogicalFontInstance.
  *
  * Nowadays there is not really a reason to have separate files for the classes, as the FreetypeManager
  * is just about handling of Freetype based fonts, not some abstract glyphs.
  *
  * One additional note: the byte-size based garbage collection of unused fonts can currently be assumed
  * to be broken. Since the move of the glyph rect cache into the ImplFontCache, so it can be used by all
  * platforms, it just takes too long to kick-in, as there is no real accounting left.
  **/
class VCL_DLLPUBLIC FreetypeManager final
{
@@ -89,23 +85,9 @@ public:

    void                    AnnounceFonts( PhysicalFontCollection* ) const;

    FreetypeFont*           CacheFont(LogicalFontInstance* pFontInstance);
    void                    UncacheFont( FreetypeFont& );

    /** Try to GarbageCollect an explicit logical font
     *
     * This should just be called from the ~ImplFontCache destructor, which holds the mapping of the
     * FontSelectPattern to the LogicalFontInstance per OutputDevice. All other users should just
     * call CacheFont and UncacheFont correctly. When the ImplFontCache is destroyed with its
     * OutputDevice, we can safely garbage collection its unused entries, as these can't be reused.
     *
     * It's always safe to call this, as it just ignores the used bytes when considering a font for
     * garbage collection, which normally keeps unreferenced fonts alive.
     **/
    void TryGarbageCollectFont(LogicalFontInstance*);

    void                    ClearFontCache();
    void                    ClearFontOptions();

    FreetypeFont*           CreateFont(FreetypeFontInstance* pLogicalFont);

private:
    // to access the constructor (can't use InitFreetypeManager function, because it's private?!)
@@ -113,23 +95,11 @@ private:
    explicit FreetypeManager();

    static void             InitFreetype();
    void                    GarbageCollect();
    FreetypeFont*           CreateFont(LogicalFontInstance* pLogicalFont);
    FreetypeFontFile* FindFontFile(const OString& rNativeFileName);

    // the FreetypeManager's FontList matches a font request to a serverfont instance
    // the FontList key's mpFontData member is reinterpreted as integer font id
    struct IFSD_Equal{  bool operator()( const rtl::Reference<LogicalFontInstance>&, const rtl::Reference<LogicalFontInstance>& ) const; };
    struct IFSD_Hash{ size_t operator()( const rtl::Reference<LogicalFontInstance>& ) const; };
    typedef std::unordered_map<rtl::Reference<LogicalFontInstance>,std::unique_ptr<FreetypeFont>,IFSD_Hash,IFSD_Equal > FontList;
    typedef std::unordered_map<sal_IntPtr, std::unique_ptr<FreetypeFontInfo>> FontInfoList;
    typedef std::unordered_map<sal_IntPtr, std::shared_ptr<FreetypeFontInfo>> FontInfoList;
    typedef std::unordered_map<const char*, std::unique_ptr<FreetypeFontFile>, rtl::CStringHash, rtl::CStringEqual> FontFileList;

    FontList                maFontList;
    static constexpr sal_uLong gnMaxSize = 1500000;  // max overall cache size in bytes
    mutable sal_uLong       mnBytesUsed;
    FreetypeFont*           mpCurrentGCFont;

    FontInfoList            m_aFontInfoList;
    sal_IntPtr              m_nMaxFontId;

@@ -148,7 +118,6 @@ public:
    FT_Face                 GetFtFace() const;
    int                     GetLoadFlags() const { return (mnLoadFlags & ~FT_LOAD_IGNORE_TRANSFORM); }
    const FontConfigFontOptions* GetFontOptions() const;
    void                    ClearFontOptions();
    bool                    NeedsArtificialBold() const { return mbArtBold; }
    bool                    NeedsArtificialItalic() const { return mbArtItalic; }

@@ -161,7 +130,7 @@ public:
    bool                    GetGlyphOutline(sal_GlyphId, basegfx::B2DPolyPolygon&, bool) const;
    bool                    GetAntialiasAdvice() const;

    FreetypeFontInstance*   GetFontInstance() const { return mpFontInstance.get(); }
    FreetypeFontInstance&   GetFontInstance() const { return mrFontInstance; }

    void                    SetFontVariationsOnHBFont(hb_font_t* pHbFace) const;

@@ -172,26 +141,14 @@ public:
    static bool             AlmostHorizontalDrainsRenderingPool(int nRatio, const FontSelectPattern& rFSD);

private:
    friend class FreetypeFontInstance;
    friend class FreetypeManager;
    explicit FreetypeFont(LogicalFontInstance*, FreetypeFontInfo*);

    void                    AddRef() const      { ++mnRefCount; }
    long                    GetRefCount() const { return mnRefCount; }
    long                    Release() const;
    sal_uLong               GetByteCount() const { return mnBytesUsed; }

    void                    ReleaseFromGarbageCollect();
    explicit FreetypeFont(FreetypeFontInstance&, std::shared_ptr<FreetypeFontInfo>& rFontInfo);

    void                    ApplyGlyphTransform(bool bVertical, FT_Glyph) const;

    rtl::Reference<FreetypeFontInstance> mpFontInstance;

    // used by FreetypeManager for cache LRU algorithm
    mutable long            mnRefCount;
    mutable sal_uLong       mnBytesUsed;

    FreetypeFont*           mpPrevGCFont;
    FreetypeFont*           mpNextGCFont;
    FreetypeFontInstance& mrFontInstance;

    // 16.16 fixed point values used for a rotated font
    long                    mnCos;
@@ -199,7 +156,7 @@ private:

    int                     mnWidth;
    int                     mnPrioAntiAlias;
    FreetypeFontInfo*       mpFontInfo;
    std::shared_ptr<FreetypeFontInfo> mxFontInfo;
    FT_Int                  mnLoadFlags;
    double                  mfStretch;
    FT_FaceRec_*            maFaceFT;
diff --git a/vcl/skia/x11/textrender.cxx b/vcl/skia/x11/textrender.cxx
index a980523..13eff30 100644
--- a/vcl/skia/x11/textrender.cxx
+++ b/vcl/skia/x11/textrender.cxx
@@ -31,7 +31,7 @@
void SkiaTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGraphics& rGraphics)
{
    const FreetypeFontInstance& rInstance = static_cast<FreetypeFontInstance&>(rLayout.GetFont());
    const FreetypeFont& rFont = *rInstance.GetFreetypeFont();
    const FreetypeFont& rFont = rInstance.GetFreetypeFont();
    const FontSelectPattern& rFSD = rInstance.GetFontSelectPattern();
    int nHeight = rFSD.mnHeight;
    int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight;
diff --git a/vcl/source/font/fontcache.cxx b/vcl/source/font/fontcache.cxx
index cf77f99..a37154d 100644
--- a/vcl/source/font/fontcache.cxx
+++ b/vcl/source/font/fontcache.cxx
@@ -96,9 +96,6 @@ ImplFontCache::~ImplFontCache()
{
    for (const auto & rLFI : maFontInstanceList)
    {
#if !(defined(_WIN32) || defined(MACOSX) || defined(IOS))
        FreetypeManager::get().TryGarbageCollectFont(rLFI.second.get());
#endif
        rLFI.second->mpFontCache = nullptr;
    }
}
diff --git a/vcl/source/gdi/impglyphitem.cxx b/vcl/source/gdi/impglyphitem.cxx
index 3b52144..4bb53d4 100644
--- a/vcl/source/gdi/impglyphitem.cxx
+++ b/vcl/source/gdi/impglyphitem.cxx
@@ -66,14 +66,6 @@ bool SalLayoutGlyphsImpl::IsValid() const
        return false;
    if (empty())
        return false;
#if (defined UNX && !defined MACOSX && !defined IOS)
    const FreetypeFontInstance* pFFI = dynamic_cast<FreetypeFontInstance*>(m_rFontInstance.get());
    if (pFFI && !pFFI->GetFreetypeFont())
    {
        m_rFontInstance.clear();
        return false;
    }
#endif
    return true;
}

diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx
index 8276029..e4da35f 100644
--- a/vcl/unx/generic/gdi/cairotextrender.cxx
+++ b/vcl/unx/generic/gdi/cairotextrender.cxx
@@ -115,7 +115,7 @@ namespace
void CairoTextRender::DrawTextLayout(const GenericSalLayout& rLayout, const SalGraphics& rGraphics)
{
    const FreetypeFontInstance& rInstance = static_cast<FreetypeFontInstance&>(rLayout.GetFont());
    const FreetypeFont& rFont = *rInstance.GetFreetypeFont();
    const FreetypeFont& rFont = rInstance.GetFreetypeFont();

    std::vector<cairo_glyph_t> cairo_glyphs;
    std::vector<int> glyph_extrarotation;
diff --git a/vcl/unx/generic/gdi/freetypetextrender.cxx b/vcl/unx/generic/gdi/freetypetextrender.cxx
index 7693eff..3d94da3 100644
--- a/vcl/unx/generic/gdi/freetypetextrender.cxx
+++ b/vcl/unx/generic/gdi/freetypetextrender.cxx
@@ -39,8 +39,6 @@
FreeTypeTextRenderImpl::FreeTypeTextRenderImpl()
    : mnTextColor(Color(0x00, 0x00, 0x00)) //black
{
    for(FreetypeFont* & rp : mpFreetypeFont)
        rp = nullptr;
}

FreeTypeTextRenderImpl::~FreeTypeTextRenderImpl()
@@ -53,51 +51,37 @@ void FreeTypeTextRenderImpl::SetFont(LogicalFontInstance *pEntry, int nFallbackL
    // release all no longer needed font resources
    for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
    {
        if( mpFreetypeFont[i] != nullptr )
        {
            // old server side font is no longer referenced
            FreetypeManager::get().UncacheFont( *mpFreetypeFont[i] );
            mpFreetypeFont[i] = nullptr;
        }
        // old server side font is no longer referenced
        mpFreetypeFont[i] = nullptr;
    }

    // return early if there is no new font
    if( !pEntry )
        return;

    // handle the request for a non-native X11-font => use the FreetypeManager
    FreetypeFont* pFreetypeFont = FreetypeManager::get().CacheFont(pEntry);
    if( pFreetypeFont != nullptr )
    {
        // ignore fonts with e.g. corrupted font files
        if( !pFreetypeFont->TestFont() )
        {
            FreetypeManager::get().UncacheFont( *pFreetypeFont );
            return;
        }
    FreetypeFontInstance* pFreetypeFont = static_cast<FreetypeFontInstance*>(pEntry);
    mpFreetypeFont[ nFallbackLevel ] = pFreetypeFont;

        // register to use the font
        mpFreetypeFont[ nFallbackLevel ] = pFreetypeFont;
    }
    // ignore fonts with e.g. corrupted font files
    if (!mpFreetypeFont[nFallbackLevel]->GetFreetypeFont().TestFont())
        mpFreetypeFont[nFallbackLevel] = nullptr;
}

FontCharMapRef FreeTypeTextRenderImpl::GetFontCharMap() const
{
    if( !mpFreetypeFont[0] )
    if (!mpFreetypeFont[0])
        return nullptr;

    return mpFreetypeFont[0]->GetFontCharMap();
    return mpFreetypeFont[0]->GetFreetypeFont().GetFontCharMap();
}

bool FreeTypeTextRenderImpl::GetFontCapabilities(vcl::FontCapabilities &rGetImplFontCapabilities) const
{
    if (!mpFreetypeFont[0])
        return false;
    return mpFreetypeFont[0]->GetFontCapabilities(rGetImplFontCapabilities);
    return mpFreetypeFont[0]->GetFreetypeFont().GetFontCapabilities(rGetImplFontCapabilities);
}

// SalGraphics

void
FreeTypeTextRenderImpl::SetTextColor( Color nColor )
{
@@ -157,8 +141,8 @@ void FreeTypeTextRenderImpl::GetFontMetric( ImplFontMetricDataRef& rxFontMetric,
    if( nFallbackLevel >= MAX_FALLBACK )
        return;

    if( mpFreetypeFont[nFallbackLevel] != nullptr )
        mpFreetypeFont[nFallbackLevel]->GetFontMetric(rxFontMetric);
    if (mpFreetypeFont[nFallbackLevel])
        mpFreetypeFont[nFallbackLevel]->GetFreetypeFont().GetFontMetric(rxFontMetric);
}

std::unique_ptr<GenericSalLayout> FreeTypeTextRenderImpl::GetTextLayout(int nFallbackLevel)
@@ -166,7 +150,7 @@ std::unique_ptr<GenericSalLayout> FreeTypeTextRenderImpl::GetTextLayout(int nFal
    assert(mpFreetypeFont[nFallbackLevel]);
    if (!mpFreetypeFont[nFallbackLevel])
        return nullptr;
    return std::make_unique<GenericSalLayout>(*mpFreetypeFont[nFallbackLevel]->GetFontInstance());
    return std::make_unique<GenericSalLayout>(*mpFreetypeFont[nFallbackLevel]);
}

#if ENABLE_CAIRO_CANVAS
@@ -177,15 +161,15 @@ SystemFontData FreeTypeTextRenderImpl::GetSysFontData( int nFallbackLevel ) cons
    if (nFallbackLevel >= MAX_FALLBACK) nFallbackLevel = MAX_FALLBACK - 1;
    if (nFallbackLevel < 0 ) nFallbackLevel = 0;

    if (mpFreetypeFont[nFallbackLevel] != nullptr)
    if (mpFreetypeFont[nFallbackLevel])
    {
        const FreetypeFont* rFont = mpFreetypeFont[nFallbackLevel];
        aSysFontData.nFontId = rFont->GetFtFace();
        aSysFontData.nFontFlags = rFont->GetLoadFlags();
        aSysFontData.bFakeBold = rFont->NeedsArtificialBold();
        aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic();
        aSysFontData.bAntialias = rFont->GetAntialiasAdvice();
        aSysFontData.bVerticalCharacterType = rFont->GetFontInstance()->GetFontSelectPattern().mbVertical;
        FreetypeFont& rFreetypeFont = mpFreetypeFont[nFallbackLevel]->GetFreetypeFont();
        aSysFontData.nFontId = rFreetypeFont.GetFtFace();
        aSysFontData.nFontFlags = rFreetypeFont.GetLoadFlags();
        aSysFontData.bFakeBold = rFreetypeFont.NeedsArtificialBold();
        aSysFontData.bFakeItalic = rFreetypeFont.NeedsArtificialItalic();
        aSysFontData.bAntialias = rFreetypeFont.GetAntialiasAdvice();
        aSysFontData.bVerticalCharacterType = mpFreetypeFont[nFallbackLevel]->GetFontSelectPattern().mbVertical;
    }

    return aSysFontData;
diff --git a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
index 08a8521..df59ce1 100644
--- a/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/freetype_glyphcache.cxx
@@ -101,7 +101,7 @@ FreetypeFontFile::FreetypeFontFile( const OString& rNativeFileName )

bool FreetypeFontFile::Map()
{
    if( mnRefCount++ <= 0 )
    if (mnRefCount++ == 0)
    {
        const char* pFileName = maNativeFileName.getStr();
        int nFile = open( pFileName, O_RDONLY );
@@ -128,11 +128,14 @@ bool FreetypeFontFile::Map()

void FreetypeFontFile::Unmap()
{
    if( (--mnRefCount > 0) || (mpFileMap == nullptr) )
    if (--mnRefCount != 0)
        return;

    munmap( mpFileMap, mnFileSize );
    mpFileMap = nullptr;
    assert(mnRefCount >= 0 && "how did this go negative\n");
    if (mpFileMap)
    {
        munmap(mpFileMap, mnFileSize);
        mpFileMap = nullptr;
    }
}

FreetypeFontInfo::FreetypeFontInfo( const FontAttributes& rDevFontAttributes,
@@ -199,7 +202,7 @@ FT_FaceRec_* FreetypeFontInfo::GetFaceFT()

void FreetypeFont::SetFontVariationsOnHBFont(hb_font_t* pHbFace) const
{
    sal_uInt32 nFaceVariation = mpFontInfo->GetFontFaceVariation();
    sal_uInt32 nFaceVariation = mxFontInfo->GetFontFaceVariation();
    if (maFaceFT && nFaceVariation)
    {
        FT_MM_Var *pFtMMVar;
@@ -223,12 +226,16 @@ void FreetypeFont::SetFontVariationsOnHBFont(hb_font_t* pHbFace) const

void FreetypeFontInfo::ReleaseFaceFT()
{
    if (--mnRefCount <= 0)
    if (--mnRefCount == 0)
    {
        FT_Done_Face( maFaceFT );
        maFaceFT = nullptr;
        if (maFaceFT)
        {
            FT_Done_Face(maFaceFT);
            maFaceFT = nullptr;
        }
        mpFontFile->Unmap();
    }
    assert(mnRefCount >= 0 && "how did this go negative\n");
}

static unsigned GetUInt( const unsigned char* p ) { return((p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]);}
@@ -360,7 +367,7 @@ void FreetypeManager::AnnounceFonts( PhysicalFontCollection* pToAdd ) const
    }
}

FreetypeFont* FreetypeManager::CreateFont(LogicalFontInstance* pFontInstance)
FreetypeFont* FreetypeManager::CreateFont(FreetypeFontInstance* pFontInstance)
{
    // find a FontInfo matching to the font id
    if (!pFontInstance)
@@ -372,12 +379,11 @@ FreetypeFont* FreetypeManager::CreateFont(LogicalFontInstance* pFontInstance)

    sal_IntPtr nFontId = pFontFace->GetFontId();
    FontInfoList::iterator it = m_aFontInfoList.find(nFontId);
    FreetypeFontInfo* pFontInfo = it != m_aFontInfoList.end() ? it->second.get() : nullptr;

    if (!pFontInfo)
    if (it == m_aFontInfoList.end())
        return nullptr;

    return new FreetypeFont(pFontInstance, pFontInfo);
    return new FreetypeFont(*pFontInstance, it->second);
}

FreetypeFontFace::FreetypeFontFace( FreetypeFontInfo* pFI, const FontAttributes& rDFA )
@@ -393,16 +399,12 @@ rtl::Reference<LogicalFontInstance> FreetypeFontFace::CreateFontInstance(const F

// FreetypeFont

FreetypeFont::FreetypeFont(LogicalFontInstance* pFontInstance, FreetypeFontInfo* pFI )
:   mpFontInstance(static_cast<FreetypeFontInstance*>(pFontInstance)),
    mnRefCount(1),
    mnBytesUsed( sizeof(FreetypeFont) ),
    mpPrevGCFont( nullptr ),
    mpNextGCFont( nullptr ),
FreetypeFont::FreetypeFont(FreetypeFontInstance& rFontInstance, std::shared_ptr<FreetypeFontInfo>& rFI)
:   mrFontInstance(rFontInstance),
    mnCos( 0x10000),
    mnSin( 0 ),
    mnPrioAntiAlias(nDefaultPrioAntiAlias),
    mpFontInfo( pFI ),
    mxFontInfo(rFI),
    mnLoadFlags( 0 ),
    maFaceFT( nullptr ),
    maSizeFT( nullptr ),
@@ -411,13 +413,10 @@ FreetypeFont::FreetypeFont(LogicalFontInstance* pFontInstance, FreetypeFontInfo*
    mbArtBold(false)
{
    int nPrioEmbedded = nDefaultPrioEmbedded;
    // TODO: move update of mpFontInstance into FontEntry class when
    // it becomes responsible for the FreetypeFont instantiation
    mpFontInstance->SetFreetypeFont( this );

    maFaceFT = pFI->GetFaceFT();
    maFaceFT = mxFontInfo->GetFaceFT();

    const FontSelectPattern& rFSD = pFontInstance->GetFontSelectPattern();
    const FontSelectPattern& rFSD = rFontInstance.GetFontSelectPattern();

    if( rFSD.mnOrientation != 0 )
    {
@@ -446,7 +445,7 @@ FreetypeFont::FreetypeFont(LogicalFontInstance* pFontInstance, FreetypeFontInfo*

    FT_Select_Charmap(maFaceFT, FT_ENCODING_UNICODE);

    if( mpFontInfo->IsSymbolFont() )
    if( mxFontInfo->IsSymbolFont() )
    {
        FT_Encoding eEncoding = FT_ENCODING_MS_SYMBOL;
        FT_Select_Charmap(maFaceFT, eEncoding);
@@ -457,8 +456,8 @@ FreetypeFont::FreetypeFont(LogicalFontInstance* pFontInstance, FreetypeFontInfo*
    // TODO: query GASP table for load flags
    mnLoadFlags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_TRANSFORM;

    mbArtItalic = (rFSD.GetItalic() != ITALIC_NONE && pFI->GetFontAttributes().GetItalic() == ITALIC_NONE);
    mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && pFI->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);
    mbArtItalic = (rFSD.GetItalic() != ITALIC_NONE && mxFontInfo->GetFontAttributes().GetItalic() == ITALIC_NONE);
    mbArtBold = (rFSD.GetWeight() > WEIGHT_MEDIUM && mxFontInfo->GetFontAttributes().GetWeight() <= WEIGHT_MEDIUM);

    if( ((mnCos != 0) && (mnSin != 0)) || (nPrioEmbedded <= 0) )
        mnLoadFlags |= FT_LOAD_NO_BITMAP;
@@ -483,30 +482,25 @@ const FontConfigFontOptions* FreetypeFont::GetFontOptions() const
{
    if (!mxFontOptions)
    {
        mxFontOptions = GetFCFontOptions(mpFontInfo->GetFontAttributes(), mpFontInstance->GetFontSelectPattern().mnHeight);
        mxFontOptions = GetFCFontOptions(mxFontInfo->GetFontAttributes(), mrFontInstance.GetFontSelectPattern().mnHeight);
        mxFontOptions->SyncPattern(GetFontFileName(), GetFontFaceIndex(), GetFontFaceVariation(), NeedsArtificialBold());
    }
    return mxFontOptions.get();
}

void FreetypeFont::ClearFontOptions()
{
    mxFontOptions.reset();
}

const OString& FreetypeFont::GetFontFileName() const
{
    return mpFontInfo->GetFontFileName();
    return mxFontInfo->GetFontFileName();
}

int FreetypeFont::GetFontFaceIndex() const
{
    return mpFontInfo->GetFontFaceIndex();
    return mxFontInfo->GetFontFaceIndex();
}

int FreetypeFont::GetFontFaceVariation() const
{
    return mpFontInfo->GetFontFaceVariation();
    return mxFontInfo->GetFontFaceVariation();
}

FreetypeFont::~FreetypeFont()
@@ -514,18 +508,14 @@ FreetypeFont::~FreetypeFont()
    if( maSizeFT )
        FT_Done_Size( maSizeFT );

    mpFontInfo->ReleaseFaceFT();

    mpFontInstance.clear();

    ReleaseFromGarbageCollect();
    mxFontInfo->ReleaseFaceFT();
}

void FreetypeFont::GetFontMetric(ImplFontMetricDataRef const & rxTo) const
{
    rxTo->FontAttributes::operator =(mpFontInfo->GetFontAttributes());
    rxTo->FontAttributes::operator =(mxFontInfo->GetFontAttributes());

    rxTo->SetOrientation( mpFontInstance->GetFontSelectPattern().mnOrientation );
    rxTo->SetOrientation(mrFontInstance.GetFontSelectPattern().mnOrientation);

    //Always consider [star]symbol as symbol fonts
    if ( IsStarSymbol( rxTo->GetFamilyName() ) )
@@ -533,7 +523,7 @@ void FreetypeFont::GetFontMetric(ImplFontMetricDataRef const & rxTo) const

    FT_Activate_Size( maSizeFT );

    rxTo->ImplCalcLineSpacing(mpFontInstance.get());
    rxTo->ImplCalcLineSpacing(&mrFontInstance);

    rxTo->SetSlant( 0 );
    rxTo->SetWidth( mnWidth );
@@ -572,13 +562,13 @@ void FreetypeFont::GetFontMetric(ImplFontMetricDataRef const & rxTo) const
    }

    // initialize kashida width
    rxTo->SetMinKashida(mpFontInstance->GetKashidaWidth());
    rxTo->SetMinKashida(mrFontInstance.GetKashidaWidth());
}

void FreetypeFont::ApplyGlyphTransform(bool bVertical, FT_Glyph pGlyphFT ) const
{
    // shortcut most common case
    if (!mpFontInstance->GetFontSelectPattern().mnOrientation && !bVertical)
    if (!mrFontInstance.GetFontSelectPattern().mnOrientation && !bVertical)
        return;

    const FT_Size_Metrics& rMetrics = maFaceFT->size->metrics;
@@ -670,14 +660,14 @@ bool FreetypeFont::GetGlyphBoundRect(sal_GlyphId nID, tools::Rectangle& rRect, b
bool FreetypeFont::GetAntialiasAdvice() const
{
    // TODO: also use GASP info
    return !mpFontInstance->GetFontSelectPattern().mbNonAntialiased && (mnPrioAntiAlias > 0);
    return !mrFontInstance.GetFontSelectPattern().mbNonAntialiased && (mnPrioAntiAlias > 0);
}

// determine unicode ranges in font

FontCharMapRef FreetypeFont::GetFontCharMap() const
{
    return mpFontInfo->GetFontCharMap();
    return mxFontInfo->GetFontCharMap();
}

const FontCharMapRef& FreetypeFontInfo::GetFontCharMap()
@@ -713,7 +703,7 @@ bool FreetypeFont::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities)
    sal_uLong nLength = 0;

    // load OS/2 table
    const FT_Byte* pOS2 = mpFontInfo->GetTable("OS/2", &nLength);
    const FT_Byte* pOS2 = mxFontInfo->GetTable("OS/2", &nLength);
    if (pOS2)
    {
        bRet = vcl::getTTCoverage(
@@ -955,7 +945,7 @@ bool FreetypeFont::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rB2

const unsigned char* FreetypeFont::GetTable(const char* pName, sal_uLong* pLength) const
{
    return mpFontInfo->GetTable( pName, pLength );
    return mxFontInfo->GetTable( pName, pLength );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/glyphs/glyphcache.cxx b/vcl/unx/generic/glyphs/glyphcache.cxx
index 40e96b9..f5f6116 100644
--- a/vcl/unx/generic/glyphs/glyphcache.cxx
+++ b/vcl/unx/generic/glyphs/glyphcache.cxx
@@ -27,9 +27,7 @@
#include <sal/log.hxx>

FreetypeManager::FreetypeManager()
:   mnBytesUsed(sizeof(FreetypeManager)),
    mpCurrentGCFont(nullptr)
    , m_nMaxFontId(0)
    : m_nMaxFontId(0)
{
    InitFreetype();
}
@@ -41,106 +39,9 @@ FreetypeManager::~FreetypeManager()

void FreetypeManager::ClearFontCache()
{
    for (auto &aFontPair : maFontList)
        static_cast<FreetypeFontInstance*>(aFontPair.first.get())->SetFreetypeFont(nullptr);
    maFontList.clear();
    mpCurrentGCFont = nullptr;
    m_aFontInfoList.clear();
}

void FreetypeManager::ClearFontOptions()
{
    for (auto const& font : maFontList)
    {
        FreetypeFont* pFreetypeFont = font.second.get();
        // free demand-loaded FontConfig related data
        pFreetypeFont->ClearFontOptions();
    }
}

static sal_IntPtr GetFontId(const LogicalFontInstance& rFontInstance)
{
    if (rFontInstance.GetFontFace())
        return rFontInstance.GetFontFace()->GetFontId();
    return 0;
}

inline
size_t FreetypeManager::IFSD_Hash::operator()(const rtl::Reference<LogicalFontInstance>& rFontInstance) const
{
    // TODO: is it worth to improve this hash function?
    sal_uIntPtr nFontId = GetFontId(*rFontInstance);

    const FontSelectPattern& rFontSelData = rFontInstance->GetFontSelectPattern();

    if (rFontSelData.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
        != -1)
    {
        OString aFeatName = OUStringToOString( rFontSelData.maTargetName, RTL_TEXTENCODING_UTF8 );
        nFontId ^= aFeatName.hashCode();
    }

    std::size_t seed = 0;
    boost::hash_combine(seed, nFontId);
    boost::hash_combine(seed, rFontSelData.mnHeight);
    boost::hash_combine(seed, rFontSelData.mnOrientation);
    boost::hash_combine(seed, size_t(rFontSelData.mbVertical));
    boost::hash_combine(seed, rFontSelData.GetItalic());
    boost::hash_combine(seed, rFontSelData.GetWeight());
    boost::hash_combine(seed, static_cast<sal_uInt16>(rFontSelData.meLanguage));
    return seed;
}

bool FreetypeManager::IFSD_Equal::operator()(const rtl::Reference<LogicalFontInstance>& rAFontInstance,
                                        const rtl::Reference<LogicalFontInstance>& rBFontInstance) const
{
    if (!rAFontInstance->GetFontCache() || !rBFontInstance->GetFontCache())
        return false;

    // check font ids
    if (GetFontId(*rAFontInstance) != GetFontId(*rBFontInstance))
        return false;

    const FontSelectPattern& rA = rAFontInstance->GetFontSelectPattern();
    const FontSelectPattern& rB = rBFontInstance->GetFontSelectPattern();

    // compare with the requested metrics
    if( (rA.mnHeight         != rB.mnHeight)
    ||  (rA.mnOrientation    != rB.mnOrientation)
    ||  (rA.mbVertical       != rB.mbVertical)
    ||  (rA.mbNonAntialiased != rB.mbNonAntialiased) )
        return false;

    if( (rA.GetItalic() != rB.GetItalic())
    ||  (rA.GetWeight() != rB.GetWeight()) )
        return false;

    // NOTE: ignoring meFamily deliberately

    // compare with the requested width, allow default width
    int nAWidth = rA.mnWidth != 0 ? rA.mnWidth : rA.mnHeight;
    int nBWidth = rB.mnWidth != 0 ? rB.mnWidth : rB.mnHeight;
    if( nAWidth != nBWidth )
        return false;

    if (rA.meLanguage != rB.meLanguage)
        return false;
   // check for features
    if ((rA.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
        != -1 ||
        rB.maTargetName.indexOf(FontSelectPattern::FEAT_PREFIX)
        != -1) && rA.maTargetName != rB.maTargetName)
        return false;

    if (rA.mbEmbolden != rB.mbEmbolden)
        return false;

    if (rA.maItalicMatrix != rB.maItalicMatrix)
        return false;

    return true;
}

FreetypeManager& FreetypeManager::get()
{
    GenericUnixSalData* const pSalData(GetGenericUnixSalData());
@@ -148,117 +49,6 @@ FreetypeManager& FreetypeManager::get()
    return *pSalData->GetFreetypeManager();
}

FreetypeFont* FreetypeManager::CacheFont(LogicalFontInstance* pFontInstance)
{
    // a serverfont request has a fontid > 0
    if (GetFontId(*pFontInstance) <= 0)
        return nullptr;

    FontList::iterator it = maFontList.find(pFontInstance);
    if( it != maFontList.end() )
    {
        FreetypeFont* pFound = it->second.get();
        assert(pFound);
        pFound->AddRef();
        return pFound;
    }

    // font not cached yet => create new font item
    FreetypeFont* pNew = CreateFont(pFontInstance);

    if( pNew )
    {
        maFontList[pFontInstance].reset(pNew);
        mnBytesUsed += pNew->GetByteCount();

        // enable garbage collection for new font
        if( !mpCurrentGCFont )
        {
            mpCurrentGCFont = pNew;
            pNew->mpNextGCFont = pNew;
            pNew->mpPrevGCFont = pNew;
        }
        else
        {
            pNew->mpNextGCFont = mpCurrentGCFont;
            pNew->mpPrevGCFont = mpCurrentGCFont->mpPrevGCFont;
            pNew->mpPrevGCFont->mpNextGCFont = pNew;
            mpCurrentGCFont->mpPrevGCFont = pNew;
        }
    }

    return pNew;
}

void FreetypeManager::UncacheFont( FreetypeFont& rFreetypeFont )
{
    if( (rFreetypeFont.Release() <= 0) && (gnMaxSize <= mnBytesUsed) )
    {
        mpCurrentGCFont = &rFreetypeFont;
        GarbageCollect();
    }
}

void FreetypeManager::TryGarbageCollectFont(LogicalFontInstance *pFontInstance)
{
    if (maFontList.empty() || !pFontInstance)
        return;
    FreetypeFontInstance* pFFI = dynamic_cast<FreetypeFontInstance*>(pFontInstance);
    if (!pFFI)
        return;
    FreetypeFont* pFreetypeFont = pFFI->GetFreetypeFont();
    if (pFreetypeFont && (pFreetypeFont->GetRefCount() <= 0))
    {
        mpCurrentGCFont = pFreetypeFont;
        GarbageCollect();
    }
}

void FreetypeManager::GarbageCollect()
{
    // when current GC font has been destroyed get another one
    if( !mpCurrentGCFont )
    {
        FontList::iterator it = maFontList.begin();
        if( it != maFontList.end() )
            mpCurrentGCFont = it->second.get();
    }

    // unless there is no other font to collect
    if( !mpCurrentGCFont )
        return;

    // prepare advance to next font for garbage collection
    FreetypeFont* const pFreetypeFont = mpCurrentGCFont;
    mpCurrentGCFont = pFreetypeFont->mpNextGCFont;

    if( (pFreetypeFont != mpCurrentGCFont)    // no other fonts
    &&  (pFreetypeFont->GetRefCount() <= 0) )  // font still used
    {
        SAL_WARN_IF( (pFreetypeFont->GetRefCount() != 0), "vcl",
            "FreetypeManager::GC detected RefCount underflow" );

        // free all pFreetypeFont related data
        if( pFreetypeFont == mpCurrentGCFont )
            mpCurrentGCFont = nullptr;
        mnBytesUsed -= pFreetypeFont->GetByteCount();

        // remove font from list of garbage collected fonts
        if( pFreetypeFont->mpPrevGCFont )
            pFreetypeFont->mpPrevGCFont->mpNextGCFont = pFreetypeFont->mpNextGCFont;
        if( pFreetypeFont->mpNextGCFont )
            pFreetypeFont->mpNextGCFont->mpPrevGCFont = pFreetypeFont->mpPrevGCFont;
        if( pFreetypeFont == mpCurrentGCFont )
            mpCurrentGCFont = nullptr;

#ifndef NDEBUG
        int nErased =
#endif
            maFontList.erase(pFreetypeFont->GetFontInstance());
        assert(1 == nErased);
    }
}

FreetypeFontFile* FreetypeManager::FindFontFile(const OString& rNativeFileName)
{
    // font file already known? (e.g. for ttc, synthetic, aliased fonts)
@@ -274,33 +64,10 @@ FreetypeFontFile* FreetypeManager::FindFontFile(const OString& rNativeFileName)
    return pFontFile;
}

void FreetypeFont::ReleaseFromGarbageCollect()
{
    // remove from GC list
    FreetypeFont* pPrev = mpPrevGCFont;
    FreetypeFont* pNext = mpNextGCFont;
    if( pPrev ) pPrev->mpNextGCFont = pNext;
    if( pNext ) pNext->mpPrevGCFont = pPrev;
    mpPrevGCFont = nullptr;
    mpNextGCFont = nullptr;
}

long FreetypeFont::Release() const
{
    SAL_WARN_IF( mnRefCount <= 0, "vcl", "FreetypeFont: RefCount underflow" );
    return --mnRefCount;
}

FreetypeFontInstance::FreetypeFontInstance(const PhysicalFontFace& rPFF, const FontSelectPattern& rFSP)
    : LogicalFontInstance(rPFF, rFSP)
    , mpFreetypeFont(nullptr)
{}

void FreetypeFontInstance::SetFreetypeFont(FreetypeFont* p)
    , mxFreetypeFont(FreetypeManager::get().CreateFont(this))
{
    if (p == mpFreetypeFont)
        return;
    mpFreetypeFont = p;
}

FreetypeFontInstance::~FreetypeFontInstance()
@@ -314,9 +81,9 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU

    sal_uLong nLength = 0;
    FreetypeFontInstance* pFontInstance = static_cast<FreetypeFontInstance*>( pUserData );
    FreetypeFont* pFont = pFontInstance->GetFreetypeFont();
    FreetypeFont& rFont = pFontInstance->GetFreetypeFont();
    const char* pBuffer = reinterpret_cast<const char*>(
        pFont->GetTable(pTagName, &nLength) );
        rFont.GetTable(pTagName, &nLength) );

    hb_blob_t* pBlob = nullptr;
    if (pBuffer != nullptr)
@@ -328,25 +95,25 @@ static hb_blob_t* getFontTable(hb_face_t* /*face*/, hb_tag_t nTableTag, void* pU
hb_font_t* FreetypeFontInstance::ImplInitHbFont()
{
    hb_font_t* pRet = InitHbFont(hb_face_create_for_tables(getFontTable, this, nullptr));
    assert(mpFreetypeFont);
    mpFreetypeFont->SetFontVariationsOnHBFont(pRet);
    assert(mxFreetypeFont);
    mxFreetypeFont->SetFontVariationsOnHBFont(pRet);
    return pRet;
}

bool FreetypeFontInstance::ImplGetGlyphBoundRect(sal_GlyphId nId, tools::Rectangle& rRect, bool bVertical) const
{
    assert(mpFreetypeFont);
    if (!mpFreetypeFont)
    assert(mxFreetypeFont);
    if (!mxFreetypeFont)
        return false;
    return mpFreetypeFont->GetGlyphBoundRect(nId, rRect, bVertical);
    return mxFreetypeFont->GetGlyphBoundRect(nId, rRect, bVertical);
}

bool FreetypeFontInstance::GetGlyphOutline(sal_GlyphId nId, basegfx::B2DPolyPolygon& rPoly, bool bVertical) const
{
    assert(mpFreetypeFont);
    if (!mpFreetypeFont)
    assert(mxFreetypeFont);
    if (!mxFreetypeFont)
        return false;
    return mpFreetypeFont->GetGlyphOutline(nId, rPoly, bVertical);
    return mxFreetypeFont->GetGlyphOutline(nId, rPoly, bVertical);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx
index 8604462..235f45e 100644
--- a/vcl/unx/generic/print/genpspgraphics.cxx
+++ b/vcl/unx/generic/print/genpspgraphics.cxx
@@ -245,13 +245,10 @@ SalPrinterBmp::GetPixelIdx (sal_uInt32 nRow, sal_uInt32 nColumn) const
/*******************************************************
 * GenPspGraphics                                         *
 *******************************************************/

GenPspGraphics::GenPspGraphics()
    : m_pJobData( nullptr ),
      m_pPrinterGfx( nullptr )
{
    for(FreetypeFont* & rp : m_pFreetypeFont)
        rp = nullptr;
}

void GenPspGraphics::Init(psp::JobData* pJob, psp::PrinterGfx* pGfx)
@@ -558,7 +555,7 @@ namespace {
class PspSalLayout : public GenericSalLayout
{
public:
    PspSalLayout(psp::PrinterGfx&, const FreetypeFont& rFont);
    PspSalLayout(psp::PrinterGfx&, LogicalFontInstance &rFontInstance);

    void                InitFont() const final override;

@@ -574,8 +571,8 @@ private:

}

PspSalLayout::PspSalLayout(::psp::PrinterGfx& rGfx, const FreetypeFont& rFont)
:   GenericSalLayout(*rFont.GetFontInstance())
PspSalLayout::PspSalLayout(::psp::PrinterGfx& rGfx, LogicalFontInstance &rFontInstance)
:   GenericSalLayout(rFontInstance)
,   mrPrinterGfx(rGfx)
{
    mnFontID     = mrPrinterGfx.GetFontID();
@@ -604,17 +601,18 @@ void GenPspGraphics::DrawTextLayout(const GenericSalLayout& rLayout)

FontCharMapRef GenPspGraphics::GetFontCharMap() const
{
    if( !m_pFreetypeFont[0] )
    if (!m_pFreetypeFont[0])
        return nullptr;

    return m_pFreetypeFont[0]->GetFontCharMap();
    return m_pFreetypeFont[0]->GetFreetypeFont().GetFontCharMap();
}

bool GenPspGraphics::GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const
{
    if (!m_pFreetypeFont[0])
        return false;
    return m_pFreetypeFont[0]->GetFontCapabilities(rFontCapabilities);

    return m_pFreetypeFont[0]->GetFreetypeFont().GetFontCapabilities(rFontCapabilities);
}

void GenPspGraphics::SetFont(LogicalFontInstance *pFontInstance, int nFallbackLevel)
@@ -622,12 +620,8 @@ void GenPspGraphics::SetFont(LogicalFontInstance *pFontInstance, int nFallbackLe
    // release all fonts that are to be overridden
    for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i )
    {
        if( m_pFreetypeFont[i] != nullptr )
        {
            // old server side font is no longer referenced
            FreetypeManager::get().UncacheFont(*m_pFreetypeFont[i]);
            m_pFreetypeFont[i] = nullptr;
        }
        // old server side font is no longer referenced
        m_pFreetypeFont[i] = nullptr;
    }

    // return early if there is no new font
@@ -656,14 +650,12 @@ void GenPspGraphics::SetFont(LogicalFontInstance *pFontInstance, int nFallbackLe

    // also set the serverside font for layouting
    // requesting a font provided by builtin rasterizer
    FreetypeFont* pFreetypeFont = FreetypeManager::get().CacheFont(pFontInstance);
    if( pFreetypeFont != nullptr )
    {
        if( pFreetypeFont->TestFont() )
            m_pFreetypeFont[ nFallbackLevel ] = pFreetypeFont;
        else
            FreetypeManager::get().UncacheFont( *pFreetypeFont );
    }
    FreetypeFontInstance* pFreetypeFont = static_cast<FreetypeFontInstance*>(pFontInstance);
    m_pFreetypeFont[ nFallbackLevel ] = pFreetypeFont;

    // ignore fonts with e.g. corrupted font files
    if (!m_pFreetypeFont[nFallbackLevel]->GetFreetypeFont().TestFont())
        m_pFreetypeFont[nFallbackLevel] = nullptr;

    // set the printer font
    m_pPrinterGfx->SetFont( nID,
@@ -749,7 +741,7 @@ void GenPspGraphics::GetFontMetric(ImplFontMetricDataRef& rxFontMetric, int nFal
        return;

    if (m_pFreetypeFont[nFallbackLevel])
        m_pFreetypeFont[nFallbackLevel]->GetFontMetric(rxFontMetric);
        m_pFreetypeFont[nFallbackLevel]->GetFreetypeFont().GetFontMetric(rxFontMetric);
}

std::unique_ptr<GenericSalLayout> GenPspGraphics::GetTextLayout(int nFallbackLevel)
diff --git a/vcl/workben/docxfuzzer.cxx b/vcl/workben/docxfuzzer.cxx
index 8976661..4e116c60 100644
--- a/vcl/workben/docxfuzzer.cxx
+++ b/vcl/workben/docxfuzzer.cxx
@@ -33,10 +33,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportDOCX(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/fodpfuzzer.cxx b/vcl/workben/fodpfuzzer.cxx
index 12bfbc3..6038497 100644
--- a/vcl/workben/fodpfuzzer.cxx
+++ b/vcl/workben/fodpfuzzer.cxx
@@ -33,10 +33,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportFODP(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/fodsfuzzer.cxx b/vcl/workben/fodsfuzzer.cxx
index 030ac14..ed9efd6 100644
--- a/vcl/workben/fodsfuzzer.cxx
+++ b/vcl/workben/fodsfuzzer.cxx
@@ -28,10 +28,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportFODS(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/fodtfuzzer.cxx b/vcl/workben/fodtfuzzer.cxx
index 2b11021..54ae266 100644
--- a/vcl/workben/fodtfuzzer.cxx
+++ b/vcl/workben/fodtfuzzer.cxx
@@ -33,10 +33,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportFODT(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/htmlfuzzer.cxx b/vcl/workben/htmlfuzzer.cxx
index fbeec9f..6da6c853 100644
--- a/vcl/workben/htmlfuzzer.cxx
+++ b/vcl/workben/htmlfuzzer.cxx
@@ -27,10 +27,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportHTML(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/mmlfuzzer.cxx b/vcl/workben/mmlfuzzer.cxx
index 02bd502..8811c27 100644
--- a/vcl/workben/mmlfuzzer.cxx
+++ b/vcl/workben/mmlfuzzer.cxx
@@ -23,10 +23,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportMML(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/pptfuzzer.cxx b/vcl/workben/pptfuzzer.cxx
index 6e725b5..d7f6b73 100644
--- a/vcl/workben/pptfuzzer.cxx
+++ b/vcl/workben/pptfuzzer.cxx
@@ -129,10 +129,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportPPT(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/pptxfuzzer.cxx b/vcl/workben/pptxfuzzer.cxx
index 021bc39..976b53d 100644
--- a/vcl/workben/pptxfuzzer.cxx
+++ b/vcl/workben/pptxfuzzer.cxx
@@ -27,10 +27,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportPPTX(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/rtffuzzer.cxx b/vcl/workben/rtffuzzer.cxx
index cc109fc..5f2ac75 100644
--- a/vcl/workben/rtffuzzer.cxx
+++ b/vcl/workben/rtffuzzer.cxx
@@ -84,10 +84,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportRTF(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/scrtffuzzer.cxx b/vcl/workben/scrtffuzzer.cxx
index 0afaf8f..779519f 100644
--- a/vcl/workben/scrtffuzzer.cxx
+++ b/vcl/workben/scrtffuzzer.cxx
@@ -77,10 +77,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportCalcRTF(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/wksfuzzer.cxx b/vcl/workben/wksfuzzer.cxx
index 617bce1..3edacb4 100644
--- a/vcl/workben/wksfuzzer.cxx
+++ b/vcl/workben/wksfuzzer.cxx
@@ -47,10 +47,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportWKS(aStream);
    // fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    // force the fontconfig options to be released now, they are demand loaded
    // so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/wmffuzzer.cxx b/vcl/workben/wmffuzzer.cxx
index ebb9c4c..7ce9ff9 100644
--- a/vcl/workben/wmffuzzer.cxx
+++ b/vcl/workben/wmffuzzer.cxx
@@ -62,10 +62,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    GDIMetaFile aGDIMetaFile;
    (void)ReadWindowMetafile(aStream, aGDIMetaFile);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/ww2fuzzer.cxx b/vcl/workben/ww2fuzzer.cxx
index 5e743ee..24038ae 100644
--- a/vcl/workben/ww2fuzzer.cxx
+++ b/vcl/workben/ww2fuzzer.cxx
@@ -98,10 +98,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportWW2(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/ww6fuzzer.cxx b/vcl/workben/ww6fuzzer.cxx
index ceba3ff..56db1198 100644
--- a/vcl/workben/ww6fuzzer.cxx
+++ b/vcl/workben/ww6fuzzer.cxx
@@ -100,10 +100,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportWW6(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/ww8fuzzer.cxx b/vcl/workben/ww8fuzzer.cxx
index cdb2cbe..d8613af 100644
--- a/vcl/workben/ww8fuzzer.cxx
+++ b/vcl/workben/ww8fuzzer.cxx
@@ -100,10 +100,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportWW8(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/xlsfuzzer.cxx b/vcl/workben/xlsfuzzer.cxx
index 14d9eea..8931109 100644
--- a/vcl/workben/xlsfuzzer.cxx
+++ b/vcl/workben/xlsfuzzer.cxx
@@ -47,10 +47,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportXLS(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}

diff --git a/vcl/workben/xlsxfuzzer.cxx b/vcl/workben/xlsxfuzzer.cxx
index 79ad9e0..a325bd6 100644
--- a/vcl/workben/xlsxfuzzer.cxx
+++ b/vcl/workben/xlsxfuzzer.cxx
@@ -25,10 +25,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
    SvMemoryStream aStream(const_cast<uint8_t*>(data), size, StreamMode::READ);
    (void)TestImportXLSX(aStream);
    //fontconfigs alloc mechanism is too complicated for lsan/valgrind so
    //force the fontconfig options to be released now, they are demand loaded
    //so will be recreated if necessary
    FreetypeManager::get().ClearFontOptions();
    return 0;
}