summaryrefslogtreecommitdiffstats
path: root/vcl/unx/generic/fontmanager/fontmanager.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /vcl/unx/generic/fontmanager/fontmanager.cxx
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vcl/unx/generic/fontmanager/fontmanager.cxx')
-rw-r--r--vcl/unx/generic/fontmanager/fontmanager.cxx736
1 files changed, 736 insertions, 0 deletions
diff --git a/vcl/unx/generic/fontmanager/fontmanager.cxx b/vcl/unx/generic/fontmanager/fontmanager.cxx
new file mode 100644
index 0000000000..a9ab5202cb
--- /dev/null
+++ b/vcl/unx/generic/fontmanager/fontmanager.cxx
@@ -0,0 +1,736 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <unistd.h>
+#include <osl/thread.h>
+
+#include <unx/fontmanager.hxx>
+#include <impfontcharmap.hxx>
+#include <unotools/syslocaleoptions.hxx>
+#include <unx/gendata.hxx>
+#include <unx/helper.hxx>
+#include <vcl/fontcharmap.hxx>
+
+#include <tools/urlobj.hxx>
+
+#include <o3tl/string_view.hxx>
+#include <osl/file.hxx>
+
+#include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
+
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <i18nlangtag/applelangid.hxx>
+
+#include <sft.hxx>
+
+#if OSL_DEBUG_LEVEL > 1
+#include <sys/times.h>
+#include <stdio.h>
+#endif
+
+#include <algorithm>
+#include <set>
+
+#ifdef CALLGRIND_COMPILE
+#include <valgrind/callgrind.h>
+#endif
+
+#include <com/sun/star/beans/XMaterialHolder.hpp>
+
+using namespace vcl;
+using namespace utl;
+using namespace psp;
+using namespace osl;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::lang;
+
+/*
+ * static helpers
+ */
+
+static sal_uInt16 getUInt16BE( const sal_uInt8*& pBuffer )
+{
+ sal_uInt16 nRet = static_cast<sal_uInt16>(pBuffer[1]) |
+ (static_cast<sal_uInt16>(pBuffer[0]) << 8);
+ pBuffer+=2;
+ return nRet;
+}
+
+/*
+ * PrintFont implementations
+ */
+PrintFontManager::PrintFont::PrintFont()
+: m_nDirectory(0)
+, m_nCollectionEntry(0)
+, m_nVariationEntry(0)
+{
+}
+
+/*
+ * one instance only
+ */
+PrintFontManager& PrintFontManager::get()
+{
+ GenericUnixSalData* const pSalData(GetGenericUnixSalData());
+ assert(pSalData);
+ return *pSalData->GetPrintFontManager();
+}
+
+/*
+ * the PrintFontManager
+ */
+
+PrintFontManager::PrintFontManager()
+ : m_nNextFontID( 1 )
+ , m_nNextDirAtom( 1 )
+ , m_aFontInstallerTimer("PrintFontManager m_aFontInstallerTimer")
+{
+ m_aFontInstallerTimer.SetInvokeHandler(LINK(this, PrintFontManager, autoInstallFontLangSupport));
+ m_aFontInstallerTimer.SetTimeout(5000);
+}
+
+PrintFontManager::~PrintFontManager()
+{
+ m_aFontInstallerTimer.Stop();
+ deinitFontconfig();
+}
+
+OString PrintFontManager::getDirectory( int nAtom ) const
+{
+ std::unordered_map< int, OString >::const_iterator it( m_aAtomToDir.find( nAtom ) );
+ return it != m_aAtomToDir.end() ? it->second : OString();
+}
+
+int PrintFontManager::getDirectoryAtom( const OString& rDirectory )
+{
+ int nAtom = 0;
+ std::unordered_map< OString, int >::const_iterator it
+ ( m_aDirToAtom.find( rDirectory ) );
+ if( it != m_aDirToAtom.end() )
+ nAtom = it->second;
+ else
+ {
+ nAtom = m_nNextDirAtom++;
+ m_aDirToAtom[ rDirectory ] = nAtom;
+ m_aAtomToDir[ nAtom ] = rDirectory;
+ }
+ return nAtom;
+}
+
+std::vector<fontID> PrintFontManager::addFontFile( std::u16string_view rFileUrl )
+{
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ INetURLObject aPath( rFileUrl );
+ OString aName(OUStringToOString(aPath.GetLastName(INetURLObject::DecodeMechanism::WithCharset, aEncoding), aEncoding));
+ OString aDir( OUStringToOString(
+ INetURLObject::decode( aPath.GetPath(), INetURLObject::DecodeMechanism::WithCharset, aEncoding ), aEncoding ) );
+
+ int nDirID = getDirectoryAtom( aDir );
+ std::vector<fontID> aFontIds = findFontFileIDs( nDirID, aName );
+ if( aFontIds.empty() )
+ {
+ addFontconfigFile(OUStringToOString(aPath.GetFull(), osl_getThreadTextEncoding()));
+
+ std::vector<PrintFont> aNewFonts = analyzeFontFile(nDirID, aName);
+ for (auto & font : aNewFonts)
+ {
+ fontID nFontId = m_nNextFontID++;
+ m_aFonts[nFontId] = std::move(font);
+ m_aFontFileToFontID[ aName ].insert( nFontId );
+ aFontIds.push_back(nFontId);
+ }
+ }
+ return aFontIds;
+}
+
+std::vector<PrintFontManager::PrintFont> PrintFontManager::analyzeFontFile( int nDirID, const OString& rFontFile, const char *pFormat ) const
+{
+ std::vector<PrintFontManager::PrintFont> aNewFonts;
+
+ OString aDir( getDirectory( nDirID ) );
+
+ OString aFullPath = aDir + "/" + rFontFile;
+
+ bool bSupported;
+ int nFD;
+ int n;
+ if (sscanf(aFullPath.getStr(), "/:FD:/%d%n", &nFD, &n) == 1 && aFullPath.getStr()[n] == '\0')
+ {
+ // Hack, pathname that actually means we will use a pre-opened file descriptor
+ bSupported = true;
+ }
+ else
+ {
+ // #i1872# reject unreadable files
+ if( access( aFullPath.getStr(), R_OK ) )
+ return aNewFonts;
+
+ bSupported = false;
+ if (pFormat)
+ {
+ if (!strcmp(pFormat, "TrueType") ||
+ !strcmp(pFormat, "CFF"))
+ bSupported = true;
+ }
+ if (!bSupported)
+ {
+ OString aExt( rFontFile.copy( rFontFile.lastIndexOf( '.' )+1 ) );
+ if( aExt.equalsIgnoreAsciiCase("ttf")
+ || aExt.equalsIgnoreAsciiCase("ttc")
+ || aExt.equalsIgnoreAsciiCase("tte") // #i33947# for Gaiji support
+ || aExt.equalsIgnoreAsciiCase("otf") ) // check for TTF- and PS-OpenType too
+ bSupported = true;
+ }
+ }
+
+ if (bSupported)
+ {
+ // get number of ttc entries
+ int nLength = CountTTCFonts( aFullPath.getStr() );
+ if (nLength > 0)
+ {
+ SAL_INFO("vcl.fonts", "ttc: " << aFullPath << " contains " << nLength << " fonts");
+
+ for( int i = 0; i < nLength; i++ )
+ {
+ PrintFont aFont;
+ aFont.m_nDirectory = nDirID;
+ aFont.m_aFontFile = rFontFile;
+ aFont.m_nCollectionEntry = i;
+ if (analyzeSfntFile(aFont))
+ aNewFonts.push_back(aFont);
+ }
+ }
+ else
+ {
+ PrintFont aFont;
+ aFont.m_nDirectory = nDirID;
+ aFont.m_aFontFile = rFontFile;
+ aFont.m_nCollectionEntry = 0;
+
+ // need to read the font anyway to get aliases inside the font file
+ if (analyzeSfntFile(aFont))
+ aNewFonts.push_back(aFont);
+ }
+ }
+ return aNewFonts;
+}
+
+fontID PrintFontManager::findFontFileID(int nDirID, const OString& rFontFile, int nFaceIndex, int nVariationIndex) const
+{
+ fontID nID = 0;
+
+ auto set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it == m_aFontFileToFontID.end() )
+ return nID;
+
+ for (fontID elem : set_it->second)
+ {
+ auto it = m_aFonts.find(elem);
+ if( it == m_aFonts.end() )
+ continue;
+ const PrintFont& rFont = (*it).second;
+ if (rFont.m_nDirectory == nDirID &&
+ rFont.m_aFontFile == rFontFile &&
+ rFont.m_nCollectionEntry == nFaceIndex &&
+ rFont.m_nVariationEntry == nVariationIndex)
+ {
+ nID = it->first;
+ if (nID)
+ break;
+ }
+ }
+
+ return nID;
+}
+
+std::vector<fontID> PrintFontManager::findFontFileIDs( int nDirID, const OString& rFontFile ) const
+{
+ std::vector<fontID> aIds;
+
+ auto set_it = m_aFontFileToFontID.find( rFontFile );
+ if( set_it == m_aFontFileToFontID.end() )
+ return aIds;
+
+ for (auto const& elem : set_it->second)
+ {
+ auto it = m_aFonts.find(elem);
+ if( it == m_aFonts.end() )
+ continue;
+ const PrintFont& rFont = (*it).second;
+ if (rFont.m_nDirectory == nDirID &&
+ rFont.m_aFontFile == rFontFile)
+ aIds.push_back(it->first);
+ }
+
+ return aIds;
+}
+
+namespace {
+
+OUString convertSfntName( const NameRecord& rNameRecord )
+{
+ OUString aValue;
+ if(
+ ( rNameRecord.platformID == 3 && ( rNameRecord.encodingID == 0 || rNameRecord.encodingID == 1 ) ) // MS, Unicode
+ ||
+ ( rNameRecord.platformID == 0 ) // Apple, Unicode
+ )
+ {
+ OUStringBuffer aName( rNameRecord.sptr.size()/2 );
+ const sal_uInt8* pNameBuffer = rNameRecord.sptr.data();
+ for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ )
+ aName.append( static_cast<sal_Unicode>(getUInt16BE( pNameBuffer )) );
+ aValue = aName.makeStringAndClear();
+ }
+ else if( rNameRecord.platformID == 3 )
+ {
+ if( rNameRecord.encodingID >= 2 && rNameRecord.encodingID <= 6 )
+ {
+ /*
+ * and now for a special kind of madness:
+ * some fonts encode their byte value string as BE uint16
+ * (leading to stray zero bytes in the string)
+ * while others code two bytes as a uint16 and swap to BE
+ */
+ OStringBuffer aName;
+ const sal_uInt8* pNameBuffer = rNameRecord.sptr.data();
+ for(size_t n = 0; n < rNameRecord.sptr.size()/2; n++ )
+ {
+ sal_Unicode aCode = static_cast<sal_Unicode>(getUInt16BE( pNameBuffer ));
+ char aChar = aCode >> 8;
+ if( aChar )
+ aName.append( aChar );
+ aChar = aCode & 0x00ff;
+ if( aChar )
+ aName.append( aChar );
+ }
+ switch( rNameRecord.encodingID )
+ {
+ case 2:
+ aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_932 );
+ break;
+ case 3:
+ aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_936 );
+ break;
+ case 4:
+ aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_950 );
+ break;
+ case 5:
+ aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_949 );
+ break;
+ case 6:
+ aValue = OStringToOUString( aName, RTL_TEXTENCODING_MS_1361 );
+ break;
+ }
+ }
+ }
+ else if( rNameRecord.platformID == 1 )
+ {
+ std::string_view aName(reinterpret_cast<const char*>(rNameRecord.sptr.data()), rNameRecord.sptr.size());
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+ switch (rNameRecord.encodingID)
+ {
+ case 0:
+ eEncoding = RTL_TEXTENCODING_APPLE_ROMAN;
+ break;
+ case 1:
+ eEncoding = RTL_TEXTENCODING_APPLE_JAPANESE;
+ break;
+ case 2:
+ eEncoding = RTL_TEXTENCODING_APPLE_CHINTRAD;
+ break;
+ case 3:
+ eEncoding = RTL_TEXTENCODING_APPLE_KOREAN;
+ break;
+ case 4:
+ eEncoding = RTL_TEXTENCODING_APPLE_ARABIC;
+ break;
+ case 5:
+ eEncoding = RTL_TEXTENCODING_APPLE_HEBREW;
+ break;
+ case 6:
+ eEncoding = RTL_TEXTENCODING_APPLE_GREEK;
+ break;
+ case 7:
+ eEncoding = RTL_TEXTENCODING_APPLE_CYRILLIC;
+ break;
+ case 9:
+ eEncoding = RTL_TEXTENCODING_APPLE_DEVANAGARI;
+ break;
+ case 10:
+ eEncoding = RTL_TEXTENCODING_APPLE_GURMUKHI;
+ break;
+ case 11:
+ eEncoding = RTL_TEXTENCODING_APPLE_GUJARATI;
+ break;
+ case 21:
+ eEncoding = RTL_TEXTENCODING_APPLE_THAI;
+ break;
+ case 25:
+ eEncoding = RTL_TEXTENCODING_APPLE_CHINSIMP;
+ break;
+ case 29:
+ eEncoding = RTL_TEXTENCODING_APPLE_CENTEURO;
+ break;
+ case 32: //Uninterpreted
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ break;
+ default:
+ if (o3tl::starts_with(aName, "Khmer OS") || // encoding '20' (Khmer) isn't implemented
+ o3tl::starts_with(aName, "YoavKtav")) // tdf#152278
+ {
+ eEncoding = RTL_TEXTENCODING_UTF8;
+ }
+ SAL_WARN_IF(eEncoding == RTL_TEXTENCODING_DONTKNOW, "vcl.fonts", "mac encoding " <<
+ rNameRecord.encodingID << " in font '" << aName << "'" <<
+ (rNameRecord.encodingID > 32 ? " is invalid" : " has unimplemented conversion"));
+ break;
+ }
+ if (eEncoding != RTL_TEXTENCODING_DONTKNOW)
+ aValue = OStringToOUString(aName, eEncoding);
+ }
+
+ return aValue;
+}
+
+OUString analyzeSfntFamilyName(void const * pTTFont)
+{
+ OUString aFamily;
+
+ std::vector<NameRecord> aNameRecords;
+ GetTTNameRecords( static_cast<TrueTypeFont const *>(pTTFont), aNameRecords );
+ if( !aNameRecords.empty() )
+ {
+ LanguageTag aUILang(SvtSysLocaleOptions().GetRealUILanguageTag());
+ LanguageType eLang = aUILang.getLanguageType();
+ int nLastMatch = -1;
+ for( size_t i = 0; i < aNameRecords.size(); i++ )
+ {
+ if( aNameRecords[i].nameID != 1 || aNameRecords[i].sptr.empty() )
+ continue;
+ int nMatch = -1;
+ if( aNameRecords[i].platformID == 0 ) // Unicode
+ nMatch = 4000;
+ else if( aNameRecords[i].platformID == 3 )
+ {
+ // this bases on the LanguageType actually being a Win LCID
+ if (aNameRecords[i].languageID == eLang)
+ nMatch = 8000;
+ else if( aNameRecords[i].languageID == LANGUAGE_ENGLISH_US )
+ nMatch = 2000;
+ else if( aNameRecords[i].languageID == LANGUAGE_ENGLISH ||
+ aNameRecords[i].languageID == LANGUAGE_ENGLISH_UK )
+ nMatch = 1500;
+ else
+ nMatch = 1000;
+ }
+ else if (aNameRecords[i].platformID == 1)
+ {
+ AppleLanguageId aAppleId = static_cast<AppleLanguageId>(static_cast<sal_uInt16>(aNameRecords[i].languageID));
+ LanguageTag aApple(makeLanguageTagFromAppleLanguageId(aAppleId));
+ if (aApple == aUILang)
+ nMatch = 8000;
+ else if (aAppleId == AppleLanguageId::ENGLISH)
+ nMatch = 2000;
+ else
+ nMatch = 1000;
+ }
+ OUString aName = convertSfntName( aNameRecords[i] );
+ if (!(aName.isEmpty()) && nMatch > nLastMatch)
+ {
+ nLastMatch = nMatch;
+ aFamily = aName;
+ }
+ }
+ }
+
+ return aFamily;
+}
+
+}
+
+bool PrintFontManager::analyzeSfntFile( PrintFont& rFont ) const
+{
+ bool bSuccess = false;
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ OString aFile = getFontFile( rFont );
+ TrueTypeFont* pTTFont = nullptr;
+
+ auto& rDFA = rFont.m_aFontAttributes;
+ rDFA.SetQuality(512);
+
+ auto const e = OpenTTFontFile( aFile.getStr(), rFont.m_nCollectionEntry, &pTTFont );
+ if( e == SFErrCodes::Ok )
+ {
+ TTGlobalFontInfo aInfo;
+ GetTTGlobalFontInfo( pTTFont, & aInfo );
+
+ if (rDFA.GetFamilyName().isEmpty())
+ {
+ OUString aFamily = analyzeSfntFamilyName(pTTFont);
+ if (aFamily.isEmpty())
+ {
+ // poor font does not have a family name
+ // name it to file name minus the extension
+ sal_Int32 dotIndex = rFont.m_aFontFile.lastIndexOf('.');
+ if ( dotIndex == -1 )
+ dotIndex = rFont.m_aFontFile.getLength();
+ aFamily = OStringToOUString(rFont.m_aFontFile.subView(0, dotIndex), aEncoding);
+ }
+
+ rDFA.SetFamilyName(aFamily);
+ }
+
+ if( !aInfo.usubfamily.isEmpty() )
+ rDFA.SetStyleName(aInfo.usubfamily);
+
+ rDFA.SetFamilyType(matchFamilyName(rDFA.GetFamilyName()));
+
+ switch( aInfo.weight )
+ {
+ case FW_THIN: rDFA.SetWeight(WEIGHT_THIN); break;
+ case FW_EXTRALIGHT: rDFA.SetWeight(WEIGHT_ULTRALIGHT); break;
+ case FW_LIGHT: rDFA.SetWeight(WEIGHT_LIGHT); break;
+ case FW_MEDIUM: rDFA.SetWeight(WEIGHT_MEDIUM); break;
+ case FW_SEMIBOLD: rDFA.SetWeight(WEIGHT_SEMIBOLD); break;
+ case FW_BOLD: rDFA.SetWeight(WEIGHT_BOLD); break;
+ case FW_EXTRABOLD: rDFA.SetWeight(WEIGHT_ULTRABOLD); break;
+ case FW_BLACK: rDFA.SetWeight(WEIGHT_BLACK); break;
+
+ case FW_NORMAL:
+ default: rDFA.SetWeight(WEIGHT_NORMAL); break;
+ }
+
+ switch( aInfo.width )
+ {
+ case FWIDTH_ULTRA_CONDENSED: rDFA.SetWidthType(WIDTH_ULTRA_CONDENSED); break;
+ case FWIDTH_EXTRA_CONDENSED: rDFA.SetWidthType(WIDTH_EXTRA_CONDENSED); break;
+ case FWIDTH_CONDENSED: rDFA.SetWidthType(WIDTH_CONDENSED); break;
+ case FWIDTH_SEMI_CONDENSED: rDFA.SetWidthType(WIDTH_SEMI_CONDENSED); break;
+ case FWIDTH_SEMI_EXPANDED: rDFA.SetWidthType(WIDTH_SEMI_EXPANDED); break;
+ case FWIDTH_EXPANDED: rDFA.SetWidthType(WIDTH_EXPANDED); break;
+ case FWIDTH_EXTRA_EXPANDED: rDFA.SetWidthType(WIDTH_EXTRA_EXPANDED); break;
+ case FWIDTH_ULTRA_EXPANDED: rDFA.SetWidthType(WIDTH_ULTRA_EXPANDED); break;
+
+ case FWIDTH_NORMAL:
+ default: rDFA.SetWidthType(WIDTH_NORMAL); break;
+ }
+
+ rDFA.SetPitch(aInfo.pitch ? PITCH_FIXED : PITCH_VARIABLE);
+ rDFA.SetItalic(aInfo.italicAngle == 0 ? ITALIC_NONE : (aInfo.italicAngle < 0 ? ITALIC_NORMAL : ITALIC_OBLIQUE));
+ // #104264# there are fonts that set italic angle 0 although they are
+ // italic; use macstyle bit here
+ if( aInfo.italicAngle == 0 && (aInfo.macStyle & 2) )
+ rDFA.SetItalic(ITALIC_NORMAL);
+
+ rDFA.SetMicrosoftSymbolEncoded(aInfo.microsoftSymbolEncoded);
+
+ CloseTTFont( pTTFont );
+ bSuccess = true;
+ }
+ else
+ SAL_WARN("vcl.fonts", "Could not OpenTTFont \"" << aFile << "\": " << int(e));
+
+ return bSuccess;
+}
+
+void PrintFontManager::initialize()
+{
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_TOGGLE_COLLECT();
+ CALLGRIND_ZERO_STATS();
+ #endif
+
+ // initialize can be called more than once, e.g.
+ // gtk-fontconfig-timestamp changes to reflect new font installed and
+ // PrintFontManager::initialize called again
+ {
+ m_nNextFontID = 1;
+ m_aFonts.clear();
+ }
+#if OSL_DEBUG_LEVEL > 1
+ clock_t aStart;
+ clock_t aStep1;
+ clock_t aStep2;
+
+ struct tms tms;
+
+ aStart = times( &tms );
+#endif
+
+ // first try fontconfig
+ initFontconfig();
+
+ // part one - look for downloadable fonts
+ rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
+ const OUString &rSalPrivatePath = psp::getFontPath();
+
+ // search for the fonts in SAL_PRIVATE_FONTPATH first; those are
+ // the fonts installed with the office
+ if( !rSalPrivatePath.isEmpty() )
+ {
+ OString aPath = OUStringToOString( rSalPrivatePath, aEncoding );
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OString aToken = aPath.getToken( 0, ';', nIndex );
+ normPath( aToken );
+ if (!aToken.isEmpty())
+ addFontconfigDir(aToken);
+ } while( nIndex >= 0 );
+ }
+
+ countFontconfigFonts();
+
+#if OSL_DEBUG_LEVEL > 1
+ aStep1 = times( &tms );
+
+ aStep2 = times( &tms );
+ SAL_INFO("vcl.fonts", "PrintFontManager::initialize: collected "
+ << m_aFonts.size()
+ << " fonts.");
+ double fTick = (double)sysconf( _SC_CLK_TCK );
+ SAL_INFO("vcl.fonts", "Step 1 took "
+ << ((double)(aStep1 - aStart)/fTick)
+ << " seconds.");
+ SAL_INFO("vcl.fonts", "Step 2 took "
+ << ((double)(aStep2 - aStep1)/fTick)
+ << " seconds.");
+#endif
+
+ #ifdef CALLGRIND_COMPILE
+ CALLGRIND_DUMP_STATS();
+ CALLGRIND_TOGGLE_COLLECT();
+ #endif
+}
+
+void PrintFontManager::getFontList( ::std::vector< fontID >& rFontIDs )
+{
+ rFontIDs.clear();
+
+ for (auto const& font : m_aFonts)
+ rFontIDs.push_back(font.first);
+}
+
+int PrintFontManager::getFontFaceNumber( fontID nFontID ) const
+{
+ int nRet = 0;
+ const PrintFont* pFont = getFont( nFontID );
+ if (pFont)
+ {
+ nRet = pFont->m_nCollectionEntry;
+ if (nRet < 0)
+ nRet = 0;
+ }
+ return nRet;
+}
+
+int PrintFontManager::getFontFaceVariation( fontID nFontID ) const
+{
+ int nRet = 0;
+ const PrintFont* pFont = getFont( nFontID );
+ if (pFont)
+ {
+ nRet = pFont->m_nVariationEntry;
+ if (nRet < 0)
+ nRet = 0;
+ }
+ return nRet;
+}
+
+FontFamily PrintFontManager::matchFamilyName( std::u16string_view rFamily )
+{
+ struct family_t {
+ const char* mpName;
+ sal_uInt16 mnLength;
+ FontFamily meType;
+ };
+
+#define InitializeClass( p, a ) p, sizeof(p) - 1, a
+ static const family_t pFamilyMatch[] = {
+ { InitializeClass( "arial", FAMILY_SWISS ) },
+ { InitializeClass( "arioso", FAMILY_SCRIPT ) },
+ { InitializeClass( "avant garde", FAMILY_SWISS ) },
+ { InitializeClass( "avantgarde", FAMILY_SWISS ) },
+ { InitializeClass( "bembo", FAMILY_ROMAN ) },
+ { InitializeClass( "bookman", FAMILY_ROMAN ) },
+ { InitializeClass( "conga", FAMILY_ROMAN ) },
+ { InitializeClass( "courier", FAMILY_MODERN ) },
+ { InitializeClass( "curl", FAMILY_SCRIPT ) },
+ { InitializeClass( "fixed", FAMILY_MODERN ) },
+ { InitializeClass( "gill", FAMILY_SWISS ) },
+ { InitializeClass( "helmet", FAMILY_MODERN ) },
+ { InitializeClass( "helvetica", FAMILY_SWISS ) },
+ { InitializeClass( "international", FAMILY_MODERN ) },
+ { InitializeClass( "lucida", FAMILY_SWISS ) },
+ { InitializeClass( "new century schoolbook", FAMILY_ROMAN ) },
+ { InitializeClass( "palatino", FAMILY_ROMAN ) },
+ { InitializeClass( "roman", FAMILY_ROMAN ) },
+ { InitializeClass( "sans serif", FAMILY_SWISS ) },
+ { InitializeClass( "sansserif", FAMILY_SWISS ) },
+ { InitializeClass( "serf", FAMILY_ROMAN ) },
+ { InitializeClass( "serif", FAMILY_ROMAN ) },
+ { InitializeClass( "times", FAMILY_ROMAN ) },
+ { InitializeClass( "utopia", FAMILY_ROMAN ) },
+ { InitializeClass( "zapf chancery", FAMILY_SCRIPT ) },
+ { InitializeClass( "zapfchancery", FAMILY_SCRIPT ) }
+ };
+
+ OString aFamily = OUStringToOString( rFamily, RTL_TEXTENCODING_ASCII_US );
+ sal_uInt32 nLower = 0;
+ sal_uInt32 nUpper = SAL_N_ELEMENTS(pFamilyMatch);
+
+ while( nLower < nUpper )
+ {
+ sal_uInt32 nCurrent = (nLower + nUpper) / 2;
+ const family_t* pHaystack = pFamilyMatch + nCurrent;
+ sal_Int32 nComparison =
+ rtl_str_compareIgnoreAsciiCase_WithLength
+ (
+ aFamily.getStr(), aFamily.getLength(),
+ pHaystack->mpName, pHaystack->mnLength
+ );
+
+ if( nComparison < 0 )
+ nUpper = nCurrent;
+ else
+ if( nComparison > 0 )
+ nLower = nCurrent + 1;
+ else
+ return pHaystack->meType;
+ }
+
+ return FAMILY_DONTKNOW;
+}
+
+OString PrintFontManager::getFontFile(const PrintFont& rFont) const
+{
+ std::unordered_map< int, OString >::const_iterator it = m_aAtomToDir.find(rFont.m_nDirectory);
+ assert(it != m_aAtomToDir.end());
+ OString aPath = it->second + "/" + rFont.m_aFontFile;
+ return aPath;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */