/* Copyright (c) 2002 Craig Drummond This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kxftconfig.h" #ifdef HAVE_FONTCONFIG #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; static int point2Pixel(double point) { return (int)(((point*QX11Info::appDpiY())/72.0)+0.5); } static int pixel2Point(double pixel) { return (int)(((pixel*72.0)/(double)QX11Info::appDpiY())+0.5); } static bool equal(double d1, double d2) { return (fabs(d1 - d2) < 0.0001); } static QString dirSyntax(const QString &d) { if(!d.isNull()) { QString ds(d); ds.replace("//", "/"); int slashPos=ds.lastIndexOf('/'); if(slashPos!=(((int)ds.length())-1)) ds.append('/'); return ds; } return d; } static bool check(const QString &path, unsigned int fmt, bool checkW=false) { KDE_struct_stat info; QByteArray pathC(QFile::encodeName(path)); return 0==KDE_lstat(pathC, &info) && (info.st_mode&S_IFMT)==fmt && (!checkW || 0==::access(pathC, W_OK)); } inline bool fExists(const QString &p) { return check(p, S_IFREG, false); } inline bool dWritable(const QString &p) { return check(p, S_IFDIR, true); } static QString getDir(const QString &f) { QString d(f); int slashPos=d.lastIndexOf('/'); if(-1!=slashPos) d.remove(slashPos+1, d.length()); return dirSyntax(d); } static time_t getTimeStamp(const QString &item) { KDE_struct_stat info; return !item.isNull() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0; } // // Obtain location of config file to use. QString getConfigFile() { FcStrList *list=FcConfigGetConfigFiles(FcConfigGetCurrent()); QStringList files; FcChar8 *file; QString home(dirSyntax(QDir::homePath())); while((file=FcStrListNext(list))) { QString f((const char *)file); if(fExists(f) && 0==f.indexOf(home)) files.append(f); } FcStrListDone(list); // // Go through list of files, looking for the preferred one... if(files.count()) { QStringList::const_iterator it(files.begin()), end(files.end()); for(; it!=end; ++it) if(-1!=(*it).indexOf(QRegExp("/\\.?fonts\\.conf$"))) return *it; return files.front(); // Just return the 1st one... } else // Hmmm... no known files? { if(FcGetVersion() >= 21000) { QString targetPath(KGlobal::dirs()->localxdgconfdir()+"fontconfig"); QDir target(targetPath); if(!target.exists()) target.mkpath(targetPath); return targetPath+"/fonts.conf"; } else return home+"/.fonts.conf"; } } static QString getEntry(QDomElement element, const char *type, unsigned int numAttributes, ...) { if(numAttributes==element.attributes().length()) { va_list args; unsigned int arg; bool ok=true; va_start(args, numAttributes); for(arg=0; arg"; static const char qtDocTypeLine[] = ""; static const char docTypeLine[] = ""; QString str(m_doc.toString()); int idx; if(0!=str.indexOf("=0 || to>=0) && foundFalse) { m_excludeRange.from=from < to ? from : to; m_excludeRange.to =from < to ? to : from; m_excludeRange.node=n; } else if((pixelFrom>=0 || pixelTo>=0) && foundFalse) { m_excludePixelRange.from=pixelFrom < pixelTo ? pixelFrom : pixelTo; m_excludePixelRange.to =pixelFrom < pixelTo ? pixelTo : pixelFrom; m_excludePixelRange.node=n; } } break; default: break; } } } n=n.nextSibling(); } } void KXftConfig::applySubPixelType() { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("const"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(toStr(m_subPixel.type)); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "rgba"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if(m_subPixel.node.isNull()) m_doc.documentElement().appendChild(matchNode); else m_doc.documentElement().replaceChild(matchNode, m_subPixel.node); m_subPixel.node=matchNode; } void KXftConfig::applyHintStyle() { applyHinting(); if(Hint::NotSet==m_hint.style || m_hint.toBeRemoved) { if(!m_hint.node.isNull()) { m_doc.documentElement().removeChild(m_hint.node); m_hint.node.clear(); } } else { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("const"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(toStr(m_hint.style)); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "hintstyle"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if(m_hint.node.isNull()) m_doc.documentElement().appendChild(matchNode); else m_doc.documentElement().replaceChild(matchNode, m_hint.node); m_hint.node=matchNode; } } void KXftConfig::applyHinting() { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("bool"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(m_hinting.set ? "true" : "false"); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "hinting"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if(m_hinting.node.isNull()) m_doc.documentElement().appendChild(matchNode); else m_doc.documentElement().replaceChild(matchNode, m_hinting.node); m_hinting.node=matchNode; } void KXftConfig::applyExcludeRange(bool pixel) { Exclude &range=pixel ? m_excludePixelRange : m_excludeRange; if(equal(range.from, 0) && equal(range.to, 0)) { if(!range.node.isNull()) { m_doc.documentElement().removeChild(range.node); range.node.clear(); } } else { QString fromString, toString; fromString.setNum(range.from); toString.setNum(range.to); QDomElement matchNode = m_doc.createElement("match"), fromTestNode = m_doc.createElement("test"), fromNode = m_doc.createElement("double"), toTestNode = m_doc.createElement("test"), toNode = m_doc.createElement("double"), editNode = m_doc.createElement("edit"), boolNode = m_doc.createElement("bool"); QDomText fromText = m_doc.createTextNode(fromString), toText = m_doc.createTextNode(toString), boolText = m_doc.createTextNode("false"); matchNode.setAttribute("target", "font"); // CPD: Is target "font" or "pattern" ???? fromTestNode.setAttribute("qual", "any"); fromTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); fromTestNode.setAttribute("compare", "more_eq"); fromTestNode.appendChild(fromNode); fromNode.appendChild(fromText); toTestNode.setAttribute("qual", "any"); toTestNode.setAttribute("name", pixel ? "pixelsize" : "size"); toTestNode.setAttribute("compare", "less_eq"); toTestNode.appendChild(toNode); toNode.appendChild(toText); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "antialias"); editNode.appendChild(boolNode); boolNode.appendChild(boolText); matchNode.appendChild(fromTestNode); matchNode.appendChild(toTestNode); matchNode.appendChild(editNode); if(!m_antiAliasing.node.isNull()) m_doc.documentElement().removeChild(range.node); m_doc.documentElement().appendChild(matchNode); range.node=matchNode; } } bool KXftConfig::getAntiAliasing() const { return m_antiAliasing.set; } void KXftConfig::setAntiAliasing( bool set ) { if(set!=m_antiAliasing.set) { m_antiAliasing.set = set; m_madeChanges = true; } } void KXftConfig::applyAntiAliasing() { QDomElement matchNode = m_doc.createElement("match"), typeNode = m_doc.createElement("bool"), editNode = m_doc.createElement("edit"); QDomText typeText = m_doc.createTextNode(m_antiAliasing.set ? "true" : "false"); matchNode.setAttribute("target", "font"); editNode.setAttribute("mode", "assign"); editNode.setAttribute("name", "antialias"); editNode.appendChild(typeNode); typeNode.appendChild(typeText); matchNode.appendChild(editNode); if(!m_antiAliasing.node.isNull()) m_doc.documentElement().removeChild(m_antiAliasing.node); m_doc.documentElement().appendChild(matchNode); m_antiAliasing.node=matchNode; } // KXftConfig only parses one config file, user's .fonts.conf usually. // If that one doesn't exist, then KXftConfig doesn't know if antialiasing // is enabled or not. So try to find out the default value from the default font. // Maybe there's a better way *shrug*. bool KXftConfig::aliasingEnabled() { FcPattern *pattern = FcPatternCreate(); FcConfigSubstitute(0, pattern, FcMatchPattern); FcDefaultSubstitute(pattern); FcResult result; FcPattern *f = FcFontMatch( 0, pattern, &result ); FcBool antialiased = FcTrue; FcPatternGetBool( f, FC_ANTIALIAS, 0, &antialiased ); FcPatternDestroy( f ); FcPatternDestroy( pattern ); return antialiased == FcTrue; } #endif