File indexing completed on 2024-06-02 05:43:46
0001 /* 0002 SPDX-FileCopyrightText: 2003-2009 Craig Drummond <craig@kde.org> 0003 SPDX-License-Identifier: GPL-2.0-or-later 0004 */ 0005 0006 #include "FcConfig.h" 0007 #include "Misc.h" 0008 #include <QByteArray> 0009 #include <QDebug> 0010 #include <QDir> 0011 #include <QDomDocument> 0012 #include <QDomElement> 0013 #include <QDomNode> 0014 #include <QDomText> 0015 #include <QFile> 0016 #include <QRegularExpression> 0017 #include <fontconfig/fontconfig.h> 0018 #include <stdio.h> 0019 0020 namespace KFI 0021 { 0022 namespace FcConfig 0023 { 0024 inline QString xDirSyntax(const QString &d) 0025 { 0026 return Misc::fileSyntax(d); 0027 } 0028 0029 // 0030 // Obtain location of config file to use. 0031 // 0032 // For system, prefer the following: 0033 // 0034 // <...>/config.d/00kde.conf = preferred method from FCConfig >= 2.3 0035 // <...>/local.conf 0036 // 0037 // Non-system, prefer: 0038 // 0039 // $HOME/<...>/.fonts.conf 0040 // $HOME/<...>/fonts.conf 0041 // 0042 QString getConfigFile(bool system) 0043 { 0044 #if (FC_VERSION >= 20300) 0045 static const char constKdeRootFcFile[] = "00kde.conf"; 0046 #endif 0047 0048 FcStrList *list = FcConfigGetConfigFiles(FcConfigGetCurrent()); 0049 QStringList files; 0050 FcChar8 *file; 0051 QString home(Misc::dirSyntax(QDir::homePath())); 0052 0053 while ((file = FcStrListNext(list))) { 0054 QString f((const char *)file); 0055 0056 if (Misc::fExists(f)) { 0057 // For nonsystem, only consider file within $HOME 0058 if (system || 0 == Misc::fileSyntax(f).indexOf(home)) { 0059 files.append(f); 0060 } 0061 } 0062 #if (FC_VERSION >= 20300) 0063 if (system && Misc::dExists(f) && (f.contains(QRegularExpression("/conf\\.d/?$")) || f.contains(QRegularExpression("/conf\\.d?$")))) { 0064 return Misc::dirSyntax(f) + constKdeRootFcFile; // This ones good enough for me! 0065 } 0066 #endif 0067 } 0068 0069 // 0070 // Go through list of files, looking for the preferred one... 0071 if (!files.isEmpty()) { 0072 QStringList::const_iterator it(files.begin()), end(files.end()); 0073 0074 for (; it != end; ++it) { 0075 if (-1 != (*it).indexOf(QRegularExpression(system ? "/local\\.conf$" : "/\\.?fonts\\.conf$"))) { 0076 return *it; 0077 } 0078 } 0079 return files.front(); // Just return the 1st one... 0080 } else { // Hmmm... no known files? 0081 return system ? "/etc/fonts/local.conf" : Misc::fileSyntax(home + "/.fonts.conf"); 0082 } 0083 } 0084 0085 void addDir(const QString &dir, bool system) 0086 { 0087 QDomDocument doc("fontconfig"); 0088 QString fileName = getConfigFile(system); 0089 QFile f(fileName); 0090 bool hasDir(false); 0091 0092 // qDebug() << "Using fontconfig file:" << fileName; 0093 0094 // Load existing file - and check to see whether it has the dir... 0095 if (f.open(QIODevice::ReadOnly)) { 0096 doc.clear(); 0097 0098 if (doc.setContent(&f)) { 0099 QDomNode n = doc.documentElement().firstChild(); 0100 0101 while (!n.isNull() && !hasDir) { 0102 QDomElement e = n.toElement(); 0103 0104 if (!e.isNull() && "dir" == e.tagName()) { 0105 if (0 == Misc::expandHome(Misc::dirSyntax(e.text())).indexOf(dir)) { 0106 hasDir = true; 0107 } 0108 } 0109 n = n.nextSibling(); 0110 } 0111 } 0112 f.close(); 0113 } 0114 0115 // Add dir, and save, if config does not already have this dir. 0116 if (!hasDir) { 0117 if (doc.documentElement().isNull()) { 0118 doc.appendChild(doc.createElement("fontconfig")); 0119 } 0120 0121 QDomElement newNode = doc.createElement("dir"); 0122 QDomText text = doc.createTextNode(Misc::contractHome(xDirSyntax(dir))); 0123 0124 newNode.appendChild(text); 0125 doc.documentElement().appendChild(newNode); 0126 0127 FcAtomic *atomic = FcAtomicCreate((const unsigned char *)(QFile::encodeName(fileName).data())); 0128 0129 if (atomic) { 0130 if (FcAtomicLock(atomic)) { 0131 FILE *f = fopen((char *)FcAtomicNewFile(atomic), "w"); 0132 0133 if (f) { 0134 // 0135 // Check document syntax... 0136 static const char qtXmlHeader[] = "<?xml version = '1.0'?>"; 0137 static const char xmlHeader[] = "<?xml version=\"1.0\"?>"; 0138 static const char qtDocTypeLine[] = "<!DOCTYPE fontconfig>"; 0139 static const char docTypeLine[] = 0140 "<!DOCTYPE fontconfig SYSTEM " 0141 "\"fonts.dtd\">"; 0142 0143 QString str(doc.toString()); 0144 int idx; 0145 0146 if (0 != str.indexOf("<?xml")) { 0147 str.insert(0, xmlHeader); 0148 } else if (0 == str.indexOf(qtXmlHeader)) { 0149 str.replace(0, strlen(qtXmlHeader), xmlHeader); 0150 } 0151 0152 if (-1 != (idx = str.indexOf(qtDocTypeLine))) { 0153 str.replace(idx, strlen(qtDocTypeLine), docTypeLine); 0154 } 0155 0156 // 0157 // Write to file... 0158 fputs(str.toUtf8(), f); 0159 fclose(f); 0160 0161 if (!FcAtomicReplaceOrig(atomic)) { 0162 FcAtomicDeleteNew(atomic); 0163 } 0164 } 0165 FcAtomicUnlock(atomic); 0166 } 0167 FcAtomicDestroy(atomic); 0168 } 0169 } 0170 } 0171 0172 } 0173 0174 }