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);
         }
     }
 

Reply via email to