diff options
author | Caolán McNamara <caolanm@redhat.com> | 2011-04-08 13:48:56 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2011-04-08 14:04:26 +0100 |
commit | 55961e2dfdac4491aa8a56d86930e5999b7d523b (patch) | |
tree | 75857326ac0d58288f1f19468b1646f77babaf5c | |
parent | f440a6fe823466ddeb809d2f4e9746e7905626d2 (diff) |
Resolves: fdo#30729 and make initial font discovery much much faster
-rw-r--r-- | vcl/unx/source/fontmanager/fontconfig.cxx | 146 |
1 files changed, 106 insertions, 40 deletions
diff --git a/vcl/unx/source/fontmanager/fontconfig.cxx b/vcl/unx/source/fontmanager/fontconfig.cxx index f34aaa147a64..c938e25c0aec 100644 --- a/vcl/unx/source/fontmanager/fontconfig.cxx +++ b/vcl/unx/source/fontmanager/fontconfig.cxx @@ -119,7 +119,7 @@ class FontCfgWrapper void (*m_pFcObjectSetDestroy)(FcObjectSet* pSet); FcPattern* (*m_pFcPatternCreate)(); void (*m_pFcPatternDestroy)(FcPattern*); - FcFontSet* (*m_pFcFontList)(FcConfig*,FcPattern*,FcObjectSet*); + FcBool (*m_pFcPatternEqual)(const FcPattern*,const FcPattern*); FcFontSet* (*m_pFcConfigGetFonts)(FcConfig*,FcSetName); FcFontSet* (*m_pFcFontSetCreate)(); FcCharSet* (*m_pFcCharSetCreate)(); @@ -199,10 +199,10 @@ public: { return m_pFcPatternCreate(); } void FcPatternDestroy( FcPattern* pPattern ) - { m_pFcPatternDestroy( pPattern ); } + { if (m_pFcPatternDestroy) m_pFcPatternDestroy( pPattern ); } - FcFontSet* FcFontList( FcConfig* pConfig, FcPattern* pPattern, FcObjectSet* pSet ) - { return m_pFcFontList( pConfig, pPattern, pSet ); } + FcBool FcPatternEqual( const FcPattern* pPatternA, const FcPattern *pPatternB ) + { return m_pFcPatternEqual( pPatternA, pPatternB ); } FcFontSet* FcConfigGetFonts( FcConfig* pConfig, FcSetName eSet) { return m_pFcConfigGetFonts( pConfig, eSet ); } @@ -341,8 +341,8 @@ FontCfgWrapper::FontCfgWrapper() loadSymbol( "FcPatternCreate" ); m_pFcPatternDestroy = (void(*)(FcPattern*)) loadSymbol( "FcPatternDestroy" ); - m_pFcFontList = (FcFontSet*(*)(FcConfig*,FcPattern*,FcObjectSet*)) - loadSymbol( "FcFontList" ); + m_pFcPatternEqual = (FcBool(*)(const FcPattern*,const FcPattern*)) + loadSymbol( "FcPatternEqual" ); m_pFcConfigGetFonts = (FcFontSet*(*)(FcConfig*,FcSetName)) loadSymbol( "FcConfigGetFonts" ); m_pFcFontSetCreate = (FcFontSet*(*)()) @@ -427,7 +427,7 @@ FontCfgWrapper::FontCfgWrapper() m_pFcObjectSetDestroy && m_pFcPatternCreate && m_pFcPatternDestroy && - m_pFcFontList && + m_pFcPatternEqual && m_pFcConfigGetFonts && m_pFcFontSetCreate && m_pFcCharSetCreate && @@ -485,45 +485,17 @@ void FontCfgWrapper::addFontSet( FcSetName eSetName ) if( !pOrig ) return; - // filter the font sets to remove obsolete or duplicate faces + // filter the font sets to remove obsolete faces for( int i = 0; i < pOrig->nfont; ++i ) { - FcPattern* pOrigPattern = pOrig->fonts[i]; + FcPattern* pPattern = pOrig->fonts[i]; // #i115131# ignore non-outline fonts FcBool bOutline = FcFalse; - FcResult eOutRes = FcPatternGetBool( pOrigPattern, FC_OUTLINE, 0, &bOutline ); + FcResult eOutRes = FcPatternGetBool( pPattern, FC_OUTLINE, 0, &bOutline ); if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) continue; - // create a pattern to find eventually better alternatives - FcPattern* pBetterPattern = pOrigPattern; - if( m_nFcVersion > 20400 ) // #i115204# avoid trouble with old FC versions - { - FcPattern* pTestPattern = FcPatternDuplicate( pOrigPattern ); - FcPatternAddBool( pTestPattern, FC_OUTLINE, FcTrue ); - // TODO: ignore all attributes that are not interesting for finding dupes - // e.g. by using pattern->ImplFontAttr->pattern conversion - FcPatternDel( pTestPattern, FC_FONTVERSION ); - FcPatternDel( pTestPattern, FC_CHARSET ); - FcPatternDel( pTestPattern, FC_FILE ); - // find the font face for the dupe-search pattern - FcResult eFcResult = FcResultMatch; - pBetterPattern = FcFontMatch( FcConfigGetCurrent(), pTestPattern, &eFcResult ); - FcPatternDestroy( pTestPattern ); - if( eFcResult != FcResultMatch ) - continue; - // #i115131# double check results and eventually ignore them - eOutRes = FcPatternGetBool( pBetterPattern, FC_OUTLINE, 0, &bOutline ); - if( (eOutRes != FcResultMatch) || (bOutline == FcFalse) ) - { - FcPatternDestroy( pBetterPattern ); - continue; - } - } - else - FcPatternReference( pBetterPattern ); - // insert best found pattern for the dupe-search pattern - // TODO: skip inserting patterns that are already known in the target fontset - FcFontSetAdd( m_pOutlineSet, pBetterPattern ); + FcPatternReference( pPattern ); + FcFontSetAdd( m_pOutlineSet, pPattern ); } // TODO?: FcFontSetDestroy( pOrig ); @@ -532,6 +504,90 @@ void FontCfgWrapper::addFontSet( FcSetName eSetName ) #endif } +#ifdef ENABLE_FONTCONFIG +namespace +{ + int compareFontNames(FontCfgWrapper& rWrapper, const FcPattern *a, const FcPattern *b) + { + FcChar8 *pNameA=NULL, *pNameB=NULL; + + bool bHaveA = rWrapper.FcPatternGetString(a, FC_FAMILY, 0, &pNameA) == FcResultMatch; + bool bHaveB = rWrapper.FcPatternGetString(b, FC_FAMILY, 0, &pNameB) == FcResultMatch; + + if (bHaveA && bHaveB) + return strcmp((const char*)pNameA, (const char*)pNameB); + + return bHaveA - bHaveB; + } + + //Sort fonts so that fonts with the same family name are side-by-side, with + //those with higher version numbers first + class SortFont : public ::std::binary_function< const FcPattern*, const FcPattern*, bool > + { + private: + FontCfgWrapper& m_rWrapper; + public: + SortFont(FontCfgWrapper& rWrapper) : m_rWrapper(rWrapper) {} + + bool operator()(const FcPattern *a, const FcPattern *b) + { + int comp = compareFontNames(m_rWrapper, a, b); + if (comp != 0) + return comp < 0; + + int nVersionA=0, nVersionB=0; + + bool bHaveA = m_rWrapper.FcPatternGetInteger(a, FC_FONTVERSION, 0, &nVersionA) == FcResultMatch; + bool bHaveB = m_rWrapper.FcPatternGetInteger(b, FC_FONTVERSION, 0, &nVersionB) == FcResultMatch; + + if (bHaveA && bHaveB) + return nVersionA > nVersionB; + + return bHaveA - bHaveA; + } + }; + + //See fdo#30729 for where an old opensymbol installed system-wide can + //clobber the new opensymbol installed locally + // + //See if this font is a duplicate with equal attributes which has already been + //inserted, or if it an older version of an inserted fonts. Depends on FcFontSet + //on being sorted with SortFont + bool isPreviouslyDuplicateOrObsoleted(FontCfgWrapper& rWrapper, FcFontSet *pFSet, int i) + { + if (i == 0) + return false; + + const FcPattern *a = pFSet->fonts[i]; + const FcPattern *b = pFSet->fonts[i-1]; + + if (compareFontNames(rWrapper, a, b) != 0) + return false; + + FcPattern* pTestPatternA = rWrapper.FcPatternDuplicate(a); + rWrapper.FcPatternDel(pTestPatternA, FC_FILE); + rWrapper.FcPatternDel(pTestPatternA, FC_CHARSET); + rWrapper.FcPatternDel(pTestPatternA, FC_CAPABILITY); + rWrapper.FcPatternDel(pTestPatternA, FC_FONTVERSION); + + FcPattern* pTestPatternB = rWrapper.FcPatternDuplicate(b); + rWrapper.FcPatternDel(pTestPatternB, FC_FILE); + rWrapper.FcPatternDel(pTestPatternB, FC_CHARSET); + rWrapper.FcPatternDel(pTestPatternB, FC_CAPABILITY); + rWrapper.FcPatternDel(pTestPatternB, FC_FONTVERSION); + + bool bIsDup = false; + if (rWrapper.FcPatternEqual(pTestPatternA, pTestPatternB)) + bIsDup = true; + + rWrapper.FcPatternDestroy(pTestPatternB); + rWrapper.FcPatternDestroy(pTestPatternA); + + return bIsDup; + } +} +#endif + FcFontSet* FontCfgWrapper::getFontSet() { #ifdef ENABLE_FONTCONFIG @@ -541,6 +597,8 @@ FcFontSet* FontCfgWrapper::getFontSet() addFontSet( FcSetSystem ); if( m_nFcVersion > 20400 ) // #i85462# prevent crashes addFontSet( FcSetApplication ); + + ::std::sort(m_pOutlineSet->fonts,m_pOutlineSet->fonts+m_pOutlineSet->nfont,SortFont(*this)); } #endif @@ -812,6 +870,14 @@ int PrintFontManager::countFontconfigFonts( boost::unordered_map<rtl::OString, i if( eOutRes == FcResultMatch && ! outline ) continue; + if (isPreviouslyDuplicateOrObsoleted(rWrapper, pFSet, i)) + { +#if OSL_DEBUG_LEVEL > 2 + fprintf(stderr, "Ditching %s as duplicate/obsolete\n", file); +#endif + continue; + } + // see if this font is already cached // update attributes std::list< PrintFont* > aFonts; |