diff options
author | Khaled Hosny <khaled@libreoffice.org> | 2023-08-03 13:44:43 +0000 |
---|---|---|
committer | خالد حسني <khaled@libreoffice.org> | 2023-08-03 19:56:08 +0200 |
commit | 0b5e88bc88df6f0cd47e84cbd8bc53b649678f8b (patch) | |
tree | 7a6f6d00120ad820f0b9a1854e93e3e6be6694f8 | |
parent | 803747fa9cb9a47e2f392d55b72033185c905e22 (diff) |
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.mcnamara@collabora.com>
Tested-by: Jenkins
Reviewed-by: خالد حسني <khaled@libreoffice.org>
-rw-r--r-- | vcl/unx/generic/fontmanager/fontconfig.cxx | 143 |
1 files changed, 43 insertions, 100 deletions
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); } } |