vcl/unx/generic/fontmanager/fontconfig.cxx | 143 ++++++++--------------------- 1 file changed, 43 insertions(+), 100 deletions(-)
New commits: commit 0b5e88bc88df6f0cd47e84cbd8bc53b649678f8b Author: Khaled Hosny <kha...@libreoffice.org> AuthorDate: Thu Aug 3 13:44:43 2023 +0000 Commit: خالد حسني <kha...@libreoffice.org> CommitDate: Thu Aug 3 19:56:08 2023 +0200 tdf#114192: Speed up populating font list when FontConfig is used Instead of calling psp::PrintFontManager::analyzeFontFile() get the font names and metadata, use the values taken from FontConfig which nowadays provides everything we need. This speeds up startup time significantly, especially when there is a large number of fonts installed. This also uses the correct style name, we were mixing name id 1 (family) with name id 17 (typographic subfamily) while we should have been using name id 2 (subfamily). The name ids 1, 2 and 16, 17 should be used together not mixed and matched, and we need the former because it is compatible with the R/I/B/BI model we (and the other office suite) use. So instead of "Foo Black, Black", we now get "Foo Black, Regular". On a system with 6616 fonts installed. Before: $ export OOO_EXIT_POST_STARTUP=1 $ time ./instdir/program/soffice.bin --headless real 0m4.744s user 0m1.672s sys 0m2.547s after: $ export OOO_EXIT_POST_STARTUP=1 $ time ./instdir/program/soffice.bin --headless real 0m1.377s user 0m0.563s sys 0m0.297s Change-Id: Ib7e358f16530c2daabc7ef677ef6a148fdf08e6e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155313 Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> Tested-by: Jenkins Reviewed-by: خالد حسني <kha...@libreoffice.org> diff --git a/vcl/unx/generic/fontmanager/fontconfig.cxx b/vcl/unx/generic/fontmanager/fontconfig.cxx index 7ceb42226d55..113171445760 100644 --- a/vcl/unx/generic/fontmanager/fontconfig.cxx +++ b/vcl/unx/generic/fontmanager/fontconfig.cxx @@ -446,6 +446,11 @@ FcResult FontCfgWrapper::LocalizedElementFromPattern(FcPattern const * pPattern, if (!m_pLanguageTag) m_pLanguageTag.reset(new LanguageTag(SvtSysLocaleOptions().GetRealUILanguageTag())); + // FontConfig orders Typographic Family/Subfamily before old + // R/B/I/BI-compatible ones, but we want the later, so reverse the + // names to match them first. + std::reverse(lang_and_elements.begin(), lang_and_elements.end()); + *element = bestname(lang_and_elements, *m_pLanguageTag); //if this element is a fontname, map the other names to this best-name @@ -545,19 +550,6 @@ namespace } } -//FontConfig doesn't come with a way to remove an element from a FontSet as far -//as I can see -static void lcl_FcFontSetRemove(FcFontSet* pFSet, int i) -{ - FcPatternDestroy(pFSet->fonts[i]); - - int nTail = pFSet->nfont - (i + 1); - --pFSet->nfont; - if (!nTail) - return; - memmove(pFSet->fonts + i, pFSet->fonts + i + 1, nTail*sizeof(FcPattern*)); -} - namespace { // for variable fonts, FC_INDEX has been changed such that the lower half is now the @@ -594,6 +586,7 @@ void PrintFontManager::countFontconfigFonts() int weight = 0; int width = 0; int spacing = 0; + int symbol = 0; int nEntryId = -1; FcBool scalable = false; @@ -607,10 +600,11 @@ void PrintFontManager::countFontconfigFonts() FcResult eWidthRes = FcPatternGetInteger(pFSet->fonts[i], FC_WIDTH, 0, &width); FcResult eSpacRes = FcPatternGetInteger(pFSet->fonts[i], FC_SPACING, 0, &spacing); FcResult eScalableRes = FcPatternGetBool(pFSet->fonts[i], FC_SCALABLE, 0, &scalable); + FcResult eSymbolRes = FcPatternGetBool(pFSet->fonts[i], FC_SYMBOL, 0, &symbol); FcResult eIndexRes = FcPatternGetInteger(pFSet->fonts[i], FC_INDEX, 0, &nEntryId); FcResult eFormatRes = FcPatternGetString(pFSet->fonts[i], FC_FONTFORMAT, 0, &format); - if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eScalableRes != FcResultMatch ) + if( eFileRes != FcResultMatch || eFamilyRes != FcResultMatch || eScalableRes != FcResultMatch || eStyleRes != FcResultMatch ) continue; SAL_INFO( @@ -623,11 +617,12 @@ void PrintFontManager::countFontconfigFonts() << (eSpacRes == FcResultMatch ? spacing : -1) << ", scalable = " << (eScalableRes == FcResultMatch ? scalable : -1) << ", format " << (eFormatRes == FcResultMatch - ? reinterpret_cast<const char*>(format) : "<unknown>")); + ? reinterpret_cast<const char*>(format) : "<unknown>") + << " symbol = " << (eSymbolRes == FcResultMatch ? symbol : -1)); // OSL_ASSERT(eScalableRes != FcResultMatch || scalable); - // only scalable fonts are usable to psprint anyway + // We support only scalable fonts if( eScalableRes == FcResultMatch && ! scalable ) continue; @@ -637,97 +632,45 @@ void PrintFontManager::countFontconfigFonts() continue; } - // see if this font is already cached - // update attributes OString aDir, aBase, aOrgPath( reinterpret_cast<char*>(file) ); splitPath( aOrgPath, aDir, aBase ); - int nDirID = getDirectoryAtom( aDir ); - SAL_INFO("vcl.fonts.detail", "file " << aBase << " not cached"); - // not known, analyze font file to get attributes - // not described by fontconfig (e.g. alias names, PSName) - if (eFormatRes != FcResultMatch) - format = nullptr; - std::vector<PrintFont> aFonts = analyzeFontFile( nDirID, aBase, reinterpret_cast<char*>(format) ); - if(aFonts.empty()) - { - SAL_INFO( - "vcl.fonts", "Warning: file \"" << aOrgPath << "\" is unusable to psprint"); - //remove font, reuse index - //we want to remove unusable fonts here, in case there is a usable font - //which duplicates the properties of the unusable one - - //not removing the unusable font will risk the usable font being rejected - //as a duplicate by isPreviouslyDuplicateOrObsoleted - lcl_FcFontSetRemove(pFSet, i--); - continue; - } - - std::optional<PrintFont> xUpdate; - if (aFonts.size() == 1) // one font - xUpdate = aFonts.front(); - else // more than one font + PrintFont aFont; + aFont.m_nDirectory = nDirID; + aFont.m_aFontFile = aBase; + if (eIndexRes == FcResultMatch) { - // a collection entry, get the correct index - if( eIndexRes == FcResultMatch && nEntryId != -1 ) - { - int nCollectionEntry = GetCollectionIndex(nEntryId); - for (const auto & font : aFonts) - { - if( font.m_nCollectionEntry == nCollectionEntry ) - { - xUpdate = font; - break; - } - } - } - - if (xUpdate) - { - // update collection entry - // additional entries will be created in the cache - // if this is a new index (that is if the loop above - // ran to the end of the list) - xUpdate->m_nCollectionEntry = GetCollectionIndex(nEntryId); - } - else - { - SAL_INFO( - "vcl.fonts", - "multiple fonts for file, but no index in fontconfig pattern ! (index res =" - << eIndexRes << " collection entry = " << nEntryId - << "; file will not be used"); - // we have found more than one font in this file - // but fontconfig will not tell us which index is meant - // -> something is in disorder, do not use this font - } + aFont.m_nCollectionEntry = GetCollectionIndex(nEntryId); + aFont.m_nVariationEntry = GetVariationIndex(nEntryId); } - if (xUpdate) - { - auto& rDFA = xUpdate->m_aFontAttributes; - // set family name - if( eWeightRes == FcResultMatch ) - rDFA.SetWeight(convertWeight(weight)); - if( eWidthRes == FcResultMatch ) - rDFA.SetWidthType(convertWidth(width)); - if( eSpacRes == FcResultMatch ) - rDFA.SetPitch(convertSpacing(spacing)); - if( eSlantRes == FcResultMatch ) - rDFA.SetItalic(convertSlant(slant)); - if( eStyleRes == FcResultMatch ) - rDFA.SetStyleName(OStringToOUString( std::string_view( reinterpret_cast<char*>(style) ), RTL_TEXTENCODING_UTF8 )); - if( eIndexRes == FcResultMatch ) - xUpdate->m_nVariationEntry = GetVariationIndex(nEntryId); - - // sort into known fonts - fontID aFont = m_nNextFontID++; - m_aFonts.emplace( aFont, *xUpdate ); - m_aFontFileToFontID[ aBase ].insert( aFont ); - nFonts++; - SAL_INFO("vcl.fonts.detail", "inserted font " << family << " as fontID " << aFont); - } + auto& rFA = aFont.m_aFontAttributes; + rFA.SetWeight(WEIGHT_NORMAL); + rFA.SetWidthType(WIDTH_NORMAL); + rFA.SetPitch(PITCH_VARIABLE); + rFA.SetQuality(512); + + rFA.SetFamilyName(OStringToOUString(std::string_view(reinterpret_cast<char*>(family)), RTL_TEXTENCODING_UTF8)); + if (eStyleRes == FcResultMatch) + rFA.SetStyleName(OStringToOUString(std::string_view(reinterpret_cast<char*>(style)), RTL_TEXTENCODING_UTF8)); + if (eWeightRes == FcResultMatch) + rFA.SetWeight(convertWeight(weight)); + if (eWidthRes == FcResultMatch) + rFA.SetWidthType(convertWidth(width)); + if (eSpacRes == FcResultMatch) + rFA.SetPitch(convertSpacing(spacing)); + if (eSlantRes == FcResultMatch) + rFA.SetItalic(convertSlant(slant)); + if (eSymbolRes == FcResultMatch) + rFA.SetMicrosoftSymbolEncoded(bool(symbol)); + + // sort into known fonts + fontID nFontID = m_nNextFontID++; + m_aFonts.emplace(nFontID, aFont); + m_aFontFileToFontID[aBase].insert(nFontID); + nFonts++; + SAL_INFO("vcl.fonts.detail", "inserted font " << family << " as fontID " << nFontID); } }