From 8c023fd645c8b83637ffcde4055886b2e4f94393 Mon Sep 17 00:00:00 2001 From: Caolán McNamara Date: Tue, 19 Jun 2012 22:23:33 +0100 Subject: Resolves: fdo#47636 cache fontconfig font substitutions But this time cache on *all* properties, not just the name, which doesn't cut it, given the things fontconfig can do, e.g. fdo#41556 Change-Id: Idfc1dbac67b6912e4985570a0b7c6ccdf47fa4a5 --- vcl/generic/fontmanager/fontsubst.cxx | 59 ++++++++++-- vcl/inc/outfont.hxx | 43 ++++++--- vcl/source/gdi/outdev3.cxx | 165 ++++++++++++++++++++++++++-------- 3 files changed, 212 insertions(+), 55 deletions(-) diff --git a/vcl/generic/fontmanager/fontsubst.cxx b/vcl/generic/fontmanager/fontsubst.cxx index 4f3ec4882b24..3f51fe50726e 100644 --- a/vcl/generic/fontmanager/fontsubst.cxx +++ b/vcl/generic/fontmanager/fontsubst.cxx @@ -42,15 +42,27 @@ #include "salprn.hxx" #include "region.h" +#include + // =========================================================================== // platform specific font substitution hooks // =========================================================================== +struct FontSelectPatternAttributesHash +{ + size_t operator()(const FontSelectPatternAttributes& rAttributes) const + { return rAttributes.hashCode(); } +}; + class FcPreMatchSubstititution : public ImplPreMatchFontSubstitution { public: bool FindFontSubstitute( FontSelectPattern& ) const; + typedef ::std::pair value_type; +private: + typedef ::std::list CachedFontMapType; + mutable CachedFontMapType maCachedFontMap; }; class FcGlyphFallbackSubstititution @@ -135,6 +147,19 @@ namespace rOrig.meWidthType == rNew.meWidthType ); } + + class equal + { + private: + const FontSelectPatternAttributes& mrAttributes; + public: + equal(const FontSelectPatternAttributes& rAttributes) + : mrAttributes(rAttributes) + { + } + bool operator()(const FcPreMatchSubstititution::value_type& rOther) const + { return rOther.first == mrAttributes; } + }; } //-------------------------------------------------------------------------- @@ -149,11 +174,26 @@ bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelDa || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) ) return false; - //Note: see fdo#41556 if you feel compelled to cache the results here, - //remember that fontconfig can return e.g. an italic font for a non-italic - //input and/or different fonts depending on fontsize, bold, etc settings so - //don't cache just on the name, cache on all the input and don't just - //return the original selection data with the fontname updated + //see fdo#41556 and fdo#47636 + //fontconfig can return e.g. an italic font for a non-italic input and/or + //different fonts depending on fontsize, bold, etc settings so don't cache + //just on the name, cache map all the input and all the output not just map + //from original selection to output fontname + FontSelectPatternAttributes& rPatternAttributes = rFontSelData; + CachedFontMapType &rCachedFontMap = const_cast(maCachedFontMap); + CachedFontMapType::iterator itr = std::find_if(rCachedFontMap.begin(), rCachedFontMap.end(), equal(rPatternAttributes)); + if (itr != rCachedFontMap.end()) + { + // Cached substitution + rFontSelData.copyAttributes(itr->second); + if (itr != rCachedFontMap.begin()) + { + // MRU, move it to the front + rCachedFontMap.splice(rCachedFontMap.begin(), rCachedFontMap, itr); + } + return true; + } + rtl::OUString aDummy; const FontSelectPattern aOut = GetFcSubstitute( rFontSelData, aDummy ); @@ -178,7 +218,14 @@ bool FcPreMatchSubstititution::FindFontSubstitute( FontSelectPattern &rFontSelDa #endif if( bHaveSubstitute ) + { + rCachedFontMap.push_front(value_type(rFontSelData, aOut)); + //fairly arbitrary limit in this case, but I recall measuring max 8 + //fonts as the typical max amount of fonts in medium sized documents + if (rCachedFontMap.size() > 8) + rCachedFontMap.pop_back(); rFontSelData = aOut; + } return bHaveSubstitute; } @@ -190,7 +237,7 @@ bool FcGlyphFallbackSubstititution::FindFontSubstitute( FontSelectPattern& rFont { // We dont' actually want to talk to Fontconfig at all for symbol fonts if( rFontSelData.IsSymbolFont() ) - return false; + return false; // StarSymbol is a unicode font, but it still deserves the symbol flag if( 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "starsymbol", 10) || 0 == rFontSelData.maSearchName.CompareIgnoreCaseToAscii( "opensymbol", 10) ) diff --git a/vcl/inc/outfont.hxx b/vcl/inc/outfont.hxx index 70398d637737..345ecc1e1207 100644 --- a/vcl/inc/outfont.hxx +++ b/vcl/inc/outfont.hxx @@ -71,6 +71,12 @@ public: // TODO: create matching interface class FontWidth GetWidthType() const { return meWidthType; } bool IsSymbolFont() const { return mbSymbolFlag; } + bool operator==(const ImplFontAttributes& rOther) const; + bool operator!=(const ImplFontAttributes& rOther) const + { + return !(*this == rOther); + } + public: // TODO: hide members behind accessor methods String maName; // Font Family Name String maStyleName; // Font Style Name @@ -109,7 +115,6 @@ public: // TODO: hide members behind accessor methods // ---------------- // - PhysicalFontFace - // ---------------- -// DONE: rename ImplFontData to PhysicalFontFace // TODO: no more direct access to members // TODO: add reference counting // TODO: get rid of height/width for scalable fonts @@ -152,24 +157,27 @@ friend class ImplDevFontListData; PhysicalFontFace* mpNext; }; -// ---------------------- -// - FontSelectPattern - -// ---------------------- - -class FontSelectPattern : public ImplFontAttributes +class FontSelectPatternAttributes : public ImplFontAttributes { public: - FontSelectPattern( const Font&, const String& rSearchName, - const Size&, float fExactHeight ); - FontSelectPattern( const PhysicalFontFace&, const Size&, - float fExactHeight, int nOrientation, bool bVertical ); + FontSelectPatternAttributes( const Font&, const String& rSearchName, + const Size&, float fExactHeight ); + FontSelectPatternAttributes( const PhysicalFontFace&, const Size&, + float fExactHeight, int nOrientation, bool bVertical ); + + size_t hashCode() const; + bool operator==(const FontSelectPatternAttributes& rOther) const; + bool operator!=(const FontSelectPatternAttributes& rOther) const + { + return !(*this == rOther); + } -public: // TODO: change to private +public: String maTargetName; // name of the font name token that is chosen String maSearchName; // name of the font that matches best int mnWidth; // width of font in pixel units int mnHeight; // height of font in pixel units - float mfExactHeight; // requested height (in pixels with subpixel details) + float mfExactHeight; // requested height (in pixels with subpixel details) int mnOrientation; // text orientation in 3600 system LanguageType meLanguage; // text language bool mbVertical; // vertical mode of requested font @@ -177,9 +185,20 @@ public: // TODO: change to private bool mbEmbolden; // Force emboldening ItalicMatrix maItalicMatrix; // Force matrix for slant +}; +class FontSelectPattern : public FontSelectPatternAttributes +{ +public: + FontSelectPattern( const Font&, const String& rSearchName, + const Size&, float fExactHeight ); + FontSelectPattern( const PhysicalFontFace&, const Size&, + float fExactHeight, int nOrientation, bool bVertical ); + +public: // TODO: change to private const PhysicalFontFace* mpFontData; // a matching PhysicalFontFace object ImplFontEntry* mpFontEntry; // pointer to the resulting FontCache entry + void copyAttributes(const FontSelectPatternAttributes &rAttributes); }; // ------------------- diff --git a/vcl/source/gdi/outdev3.cxx b/vcl/source/gdi/outdev3.cxx index 3459afc08372..fc166ae5f34c 100644 --- a/vcl/source/gdi/outdev3.cxx +++ b/vcl/source/gdi/outdev3.cxx @@ -2139,21 +2139,17 @@ ImplGetDevSizeList* ImplDevFontList::GetDevSizeList( const String& rFontName ) c return pGetDevSizeList; } -// ======================================================================= - -FontSelectPattern::FontSelectPattern( const Font& rFont, - const String& rSearchName, const Size& rSize, float fExactHeight) -: maSearchName( rSearchName ), - mnWidth( rSize.Width() ), - mnHeight( rSize.Height() ), - mfExactHeight( fExactHeight), - mnOrientation( rFont.GetOrientation() ), - meLanguage( rFont.GetLanguage() ), - mbVertical( rFont.IsVertical() ), - mbNonAntialiased( false ), - mbEmbolden( false ), - mpFontData( NULL ), - mpFontEntry( NULL ) +FontSelectPatternAttributes::FontSelectPatternAttributes( const Font& rFont, + const String& rSearchName, const Size& rSize, float fExactHeight ) + : maSearchName( rSearchName ) + , mnWidth( rSize.Width() ) + , mnHeight( rSize.Height() ) + , mfExactHeight( fExactHeight) + , mnOrientation( rFont.GetOrientation() ) + , meLanguage( rFont.GetLanguage() ) + , mbVertical( rFont.IsVertical() ) + , mbNonAntialiased( false ) + , mbEmbolden( false ) { maTargetName = maName; @@ -2175,51 +2171,115 @@ FontSelectPattern::FontSelectPattern( const Font& rFont, mnWidth = -mnWidth; } -// ----------------------------------------------------------------------- +FontSelectPattern::FontSelectPattern( const Font& rFont, + const String& rSearchName, const Size& rSize, float fExactHeight) + : FontSelectPatternAttributes(rFont, rSearchName, rSize, fExactHeight) + , mpFontData( NULL ) + , mpFontEntry( NULL ) +{ +} + // NOTE: this ctor is still used on Windows. Do not remove. -FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData, +FontSelectPatternAttributes::FontSelectPatternAttributes( const PhysicalFontFace& rFontData, const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) -: ImplFontAttributes( rFontData ), - mnWidth( rSize.Width() ), - mnHeight( rSize.Height() ), - mfExactHeight( fExactHeight ), - mnOrientation( nOrientation ), - meLanguage( 0 ), - mbVertical( bVertical ), - mbNonAntialiased( false ), - mbEmbolden( false ), - mpFontData( &rFontData ), - mpFontEntry( NULL ) + : ImplFontAttributes( rFontData ) + , mnWidth( rSize.Width() ) + , mnHeight( rSize.Height() ) + , mfExactHeight( fExactHeight ) + , mnOrientation( nOrientation ) + , meLanguage( 0 ) + , mbVertical( bVertical ) + , mbNonAntialiased( false ) + , mbEmbolden( false ) { maTargetName = maSearchName = maName; // NOTE: no normalization for width/height/orientation } +FontSelectPattern::FontSelectPattern( const PhysicalFontFace& rFontData, + const Size& rSize, float fExactHeight, int nOrientation, bool bVertical ) + : FontSelectPatternAttributes(rFontData, rSize, fExactHeight, nOrientation, bVertical) + , mpFontData( &rFontData ) + , mpFontEntry( NULL ) +{ +} + +void FontSelectPattern::copyAttributes(const FontSelectPatternAttributes &rAttributes) +{ + static_cast(*this) = rAttributes; +} + // ======================================================================= size_t ImplFontCache::IFSD_Hash::operator()( const FontSelectPattern& rFSD ) const +{ + return rFSD.hashCode(); +} + +size_t FontSelectPatternAttributes::hashCode() const { // TODO: does it pay off to improve this hash function? static FontNameHash aFontNameHash; - size_t nHash = aFontNameHash( rFSD.maSearchName ); + size_t nHash = aFontNameHash( maSearchName ); #ifdef ENABLE_GRAPHITE // check for features and generate a unique hash if necessary - if (rFSD.maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX) + if (maTargetName.Search(grutils::GrFeatureParser::FEAT_PREFIX) != STRING_NOTFOUND) { - nHash = aFontNameHash( rFSD.maTargetName ); + nHash = aFontNameHash( maTargetName ); } #endif - nHash += 11 * rFSD.mnHeight; - nHash += 19 * rFSD.meWeight; - nHash += 29 * rFSD.meItalic; - nHash += 37 * rFSD.mnOrientation; - nHash += 41 * rFSD.meLanguage; - if( rFSD.mbVertical ) + nHash += 11 * mnHeight; + nHash += 19 * meWeight; + nHash += 29 * meItalic; + nHash += 37 * mnOrientation; + nHash += 41 * meLanguage; + if( mbVertical ) nHash += 53; return nHash; } +bool FontSelectPatternAttributes::operator==(const FontSelectPatternAttributes& rOther) const +{ + if (static_cast(*this) != static_cast(rOther)) + return false; + + if (maTargetName != rOther.maTargetName) + return false; + + if (maSearchName != rOther.maSearchName) + return false; + + if (mnWidth != rOther.mnWidth) + return false; + + if (mnHeight != rOther.mnHeight) + return false; + + if (mfExactHeight != rOther.mfExactHeight) + return false; + + if (mnOrientation != rOther.mnOrientation) + return false; + + if (meLanguage != rOther.meLanguage) + return false; + + if (mbVertical != rOther.mbVertical) + return false; + + if (mbNonAntialiased != rOther.mbNonAntialiased) + return false; + + if (mbEmbolden != rOther.mbEmbolden) + return false; + + if (maItalicMatrix != rOther.maItalicMatrix) + return false; + + return true; +} + // ----------------------------------------------------------------------- bool ImplFontCache::IFSD_Equal::operator()(const FontSelectPattern& rA, const FontSelectPattern& rB) const @@ -3332,6 +3392,37 @@ void OutputDevice::ImplInitAboveTextLineSize() // ----------------------------------------------------------------------- +bool ImplFontAttributes::operator==(const ImplFontAttributes& rOther) const +{ + if (maName != rOther.maName) + return false; + + if (maStyleName != rOther.maStyleName) + return false; + + if (meWeight != rOther.meWeight) + return false; + + if (meItalic != rOther.meItalic) + return false; + + if (meFamily != rOther.meFamily) + return false; + + if (mePitch != rOther.mePitch) + return false; + + if (meWidthType != rOther.meWidthType) + return false; + + if (mbSymbolFlag != rOther.mbSymbolFlag) + return false; + + return true; +} + +// ----------------------------------------------------------------------- + ImplFontMetricData::ImplFontMetricData( const FontSelectPattern& rFontSelData ) : ImplFontAttributes( rFontSelData ) { -- cgit v1.2.3