mirror of
https://bitbucket.org/smil3y/kde-workspace.git
synced 2025-02-23 18:32:50 +00:00
847 lines
27 KiB
C++
847 lines
27 KiB
C++
/*
|
|
Copyright (c) 2002 Craig Drummond <craig@kde.org>
|
|
|
|
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 <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdlib.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <QRegExp>
|
|
#include <QFile>
|
|
#include <QDir>
|
|
#include <QtGui/qx11info_x11.h>
|
|
#include <QByteArray>
|
|
|
|
#include <KLocale>
|
|
#include <kde_file.h>
|
|
#include <KGlobal>
|
|
#include <KStandardDirs>
|
|
#include <KDebug>
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
|
|
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<numAttributes && ok; ++arg)
|
|
{
|
|
const char *attr=va_arg(args, const char *);
|
|
const char *val =va_arg(args, const char *);
|
|
|
|
if(!attr || !val || val!=element.attribute(attr))
|
|
ok=false;
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
if(ok)
|
|
{
|
|
QDomNode n=element.firstChild();
|
|
|
|
if(!n.isNull())
|
|
{
|
|
QDomElement e = n.toElement();
|
|
|
|
if(!e.isNull() && type==e.tagName())
|
|
return e.text();
|
|
}
|
|
}
|
|
}
|
|
|
|
return QString();
|
|
}
|
|
|
|
static KXftConfig::SubPixel::Type strToType(const char *str)
|
|
{
|
|
if(0==strcmp(str, "rgb"))
|
|
return KXftConfig::SubPixel::Rgb;
|
|
else if(0==strcmp(str, "bgr"))
|
|
return KXftConfig::SubPixel::Bgr;
|
|
else if(0==strcmp(str, "vrgb"))
|
|
return KXftConfig::SubPixel::Vrgb;
|
|
else if(0==strcmp(str, "vbgr"))
|
|
return KXftConfig::SubPixel::Vbgr;
|
|
else
|
|
return KXftConfig::SubPixel::None;
|
|
}
|
|
|
|
static KXftConfig::Hint::Style strToStyle(const char *str)
|
|
{
|
|
if(0==strcmp(str, "hintslight"))
|
|
return KXftConfig::Hint::Slight;
|
|
else if(0==strcmp(str, "hintmedium"))
|
|
return KXftConfig::Hint::Medium;
|
|
else if(0==strcmp(str, "hintfull"))
|
|
return KXftConfig::Hint::Full;
|
|
else
|
|
return KXftConfig::Hint::None;
|
|
}
|
|
|
|
KXftConfig::KXftConfig()
|
|
: m_doc("fontconfig")
|
|
, m_file(getConfigFile())
|
|
{
|
|
kDebug() << "Using fontconfig file:" << m_file;
|
|
m_antiAliasing = aliasingEnabled();
|
|
reset();
|
|
}
|
|
|
|
KXftConfig::~KXftConfig()
|
|
{
|
|
}
|
|
|
|
bool KXftConfig::reset()
|
|
{
|
|
bool ok=false;
|
|
|
|
m_madeChanges=false;
|
|
m_hint.reset();
|
|
m_hinting.reset();
|
|
m_excludeRange.reset();
|
|
m_excludePixelRange.reset();
|
|
m_subPixel.reset();
|
|
|
|
QFile f(m_file);
|
|
|
|
if(f.open(QIODevice::ReadOnly))
|
|
{
|
|
m_time=getTimeStamp(m_file);
|
|
ok=true;
|
|
m_doc.clear();
|
|
|
|
if(m_doc.setContent(&f))
|
|
readContents();
|
|
f.close();
|
|
}
|
|
else
|
|
ok=!fExists(m_file) && dWritable(getDir(m_file));
|
|
|
|
if(m_doc.documentElement().isNull())
|
|
m_doc.appendChild(m_doc.createElement("fontconfig"));
|
|
|
|
if(ok)
|
|
{
|
|
//
|
|
// Check exclude range values - i.e. size and pixel size...
|
|
// If "size" range is set, ensure "pixelsize" matches...
|
|
if(!equal(0, m_excludeRange.from) || !equal(0, m_excludeRange.to))
|
|
{
|
|
double pFrom=(double)point2Pixel(m_excludeRange.from),
|
|
pTo=(double)point2Pixel(m_excludeRange.to);
|
|
|
|
if(!equal(pFrom, m_excludePixelRange.from) || !equal(pTo, m_excludePixelRange.to))
|
|
{
|
|
m_excludePixelRange.from=pFrom;
|
|
m_excludePixelRange.to=pTo;
|
|
m_madeChanges=true;
|
|
apply();
|
|
}
|
|
}
|
|
else if(!equal(0, m_excludePixelRange.from) || !equal(0, m_excludePixelRange.to))
|
|
{
|
|
// "pixelsize" set, but not "size" !!!
|
|
m_excludeRange.from=(int)pixel2Point(m_excludePixelRange.from);
|
|
m_excludeRange.to=(int)pixel2Point(m_excludePixelRange.to);
|
|
m_madeChanges=true;
|
|
apply();
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool KXftConfig::apply()
|
|
{
|
|
bool ok=true;
|
|
|
|
if(m_madeChanges)
|
|
{
|
|
//
|
|
// Check if file has been written since we last read it. If it has, then re-read and add any
|
|
// of our changes...
|
|
if(fExists(m_file) && getTimeStamp(m_file)!=m_time)
|
|
{
|
|
KXftConfig newConfig;
|
|
|
|
newConfig.setExcludeRange(m_excludeRange.from, m_excludeRange.to);
|
|
newConfig.setSubPixelType(m_subPixel.type);
|
|
newConfig.setHintStyle(m_hint.style);
|
|
newConfig.setAntiAliasing(m_antiAliasing.set);
|
|
|
|
ok=newConfig.changed() ? newConfig.apply() : true;
|
|
if(ok)
|
|
reset();
|
|
else
|
|
m_time=getTimeStamp(m_file);
|
|
}
|
|
else
|
|
{
|
|
// Ensure these are always equal...
|
|
m_excludePixelRange.from=(int)point2Pixel(m_excludeRange.from);
|
|
m_excludePixelRange.to=(int)point2Pixel(m_excludeRange.to);
|
|
|
|
FcAtomic *atomic=FcAtomicCreate((const unsigned char *)(QFile::encodeName(m_file).data()));
|
|
|
|
ok=false;
|
|
if(atomic)
|
|
{
|
|
if(FcAtomicLock(atomic))
|
|
{
|
|
FILE *f=fopen((char *)FcAtomicNewFile(atomic), "w");
|
|
|
|
if(f)
|
|
{
|
|
applySubPixelType();
|
|
applyHintStyle();
|
|
applyAntiAliasing();
|
|
applyExcludeRange(false);
|
|
applyExcludeRange(true);
|
|
|
|
//
|
|
// Check document syntax...
|
|
static const char qtXmlHeader[] = "<?xml version = '1.0'?>";
|
|
static const char xmlHeader[] = "<?xml version=\"1.0\"?>";
|
|
static const char qtDocTypeLine[] = "<!DOCTYPE fontconfig>";
|
|
static const char docTypeLine[] = "<!DOCTYPE fontconfig SYSTEM "
|
|
"\"fonts.dtd\">";
|
|
|
|
QString str(m_doc.toString());
|
|
int idx;
|
|
|
|
if(0!=str.indexOf("<?xml"))
|
|
str.insert(0, xmlHeader);
|
|
else if(0==str.indexOf(qtXmlHeader))
|
|
str.replace(0, strlen(qtXmlHeader), xmlHeader);
|
|
|
|
if(-1!=(idx=str.indexOf(qtDocTypeLine)))
|
|
str.replace(idx, strlen(qtDocTypeLine), docTypeLine);
|
|
|
|
//
|
|
// Write to file...
|
|
fputs(str.toUtf8(), f);
|
|
fclose(f);
|
|
|
|
if(FcAtomicReplaceOrig(atomic))
|
|
{
|
|
ok=true;
|
|
reset(); // Re-read contents..
|
|
}
|
|
else
|
|
FcAtomicDeleteNew(atomic);
|
|
}
|
|
FcAtomicUnlock(atomic);
|
|
}
|
|
FcAtomicDestroy(atomic);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ok;
|
|
}
|
|
|
|
bool KXftConfig::getSubPixelType(SubPixel::Type &type)
|
|
{
|
|
type=m_subPixel.type;
|
|
return SubPixel::None!=m_subPixel.type;
|
|
}
|
|
|
|
void KXftConfig::setSubPixelType(SubPixel::Type type)
|
|
{
|
|
if(type!=m_subPixel.type)
|
|
{
|
|
m_subPixel.type=type;
|
|
m_madeChanges=true;
|
|
}
|
|
}
|
|
|
|
bool KXftConfig::getHintStyle(Hint::Style &style)
|
|
{
|
|
if(Hint::NotSet!=m_hint.style && !m_hint.toBeRemoved)
|
|
{
|
|
style=m_hint.style;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void KXftConfig::setHintStyle(Hint::Style style)
|
|
{
|
|
if((Hint::NotSet==style && Hint::NotSet!=m_hint.style && !m_hint.toBeRemoved) ||
|
|
(Hint::NotSet!=style && (style!=m_hint.style || m_hint.toBeRemoved)) )
|
|
{
|
|
m_hint.toBeRemoved=(Hint::NotSet==style);
|
|
m_hint.style=style;
|
|
m_madeChanges=true;
|
|
}
|
|
|
|
if(Hint::NotSet!=style)
|
|
setHinting(Hint::None!=m_hint.style);
|
|
}
|
|
|
|
void KXftConfig::setHinting(bool set)
|
|
{
|
|
if(set!=m_hinting.set)
|
|
{
|
|
m_hinting.set=set;
|
|
m_madeChanges=true;
|
|
}
|
|
}
|
|
|
|
bool KXftConfig::getExcludeRange(double &from, double &to)
|
|
{
|
|
if(!equal(0, m_excludeRange.from) || !equal(0,m_excludeRange.to))
|
|
{
|
|
from=m_excludeRange.from;
|
|
to=m_excludeRange.to;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
void KXftConfig::setExcludeRange(double from, double to)
|
|
{
|
|
double f=from<to ? from : to,
|
|
t=from<to ? to : from;
|
|
|
|
if(!equal(f, m_excludeRange.from) || !equal(t,m_excludeRange.to))
|
|
{
|
|
m_excludeRange.from=f;
|
|
m_excludeRange.to=t;
|
|
m_madeChanges=true;
|
|
}
|
|
}
|
|
|
|
QString KXftConfig::description(SubPixel::Type t)
|
|
{
|
|
switch(t)
|
|
{
|
|
default:
|
|
case SubPixel::None:
|
|
return i18nc("no subpixel rendering", "None");
|
|
case SubPixel::Rgb:
|
|
return i18n("RGB");
|
|
case SubPixel::Bgr:
|
|
return i18n("BGR");
|
|
case SubPixel::Vrgb:
|
|
return i18n("Vertical RGB");
|
|
case SubPixel::Vbgr:
|
|
return i18n("Vertical BGR");
|
|
}
|
|
}
|
|
|
|
const char * KXftConfig::toStr(SubPixel::Type t)
|
|
{
|
|
switch(t)
|
|
{
|
|
default:
|
|
case SubPixel::None:
|
|
return "none";
|
|
case SubPixel::Rgb:
|
|
return "rgb";
|
|
case SubPixel::Bgr:
|
|
return "bgr";
|
|
case SubPixel::Vrgb:
|
|
return "vrgb";
|
|
case SubPixel::Vbgr:
|
|
return "vbgr";
|
|
}
|
|
}
|
|
|
|
QString KXftConfig::description(Hint::Style s)
|
|
{
|
|
switch(s)
|
|
{
|
|
default:
|
|
case Hint::Medium:
|
|
return i18nc("medium hinting", "Medium");
|
|
case Hint::NotSet:
|
|
return "";
|
|
case Hint::None:
|
|
return i18nc("no hinting", "None");
|
|
case Hint::Slight:
|
|
return i18nc("slight hinting", "Slight");
|
|
case Hint::Full:
|
|
return i18nc("full hinting", "Full");
|
|
}
|
|
}
|
|
|
|
const char * KXftConfig::toStr(Hint::Style s)
|
|
{
|
|
switch(s)
|
|
{
|
|
default:
|
|
case Hint::Medium:
|
|
return "hintmedium";
|
|
case Hint::None:
|
|
return "hintnone";
|
|
case Hint::Slight:
|
|
return "hintslight";
|
|
case Hint::Full:
|
|
return "hintfull";
|
|
}
|
|
}
|
|
|
|
void KXftConfig::readContents()
|
|
{
|
|
QDomNode n = m_doc.documentElement().firstChild();
|
|
|
|
while(!n.isNull())
|
|
{
|
|
QDomElement e = n.toElement();
|
|
|
|
if(!e.isNull())
|
|
{
|
|
if("match"==e.tagName())
|
|
{
|
|
QString str;
|
|
|
|
switch(e.childNodes().count())
|
|
{
|
|
case 1:
|
|
if("font"==e.attribute("target"))
|
|
{
|
|
QDomElement ene=e.firstChild().toElement();
|
|
|
|
if(!ene.isNull() && "edit"==ene.tagName())
|
|
{
|
|
if(!(str=getEntry(ene, "const", 2, "name", "rgba", "mode",
|
|
"assign")).isNull())
|
|
{
|
|
m_subPixel.node=n;
|
|
m_subPixel.type=strToType(str.toLatin1());
|
|
}
|
|
else if(!(str=getEntry(ene, "const", 2, "name", "hintstyle", "mode",
|
|
"assign")).isNull())
|
|
{
|
|
m_hint.node=n;
|
|
m_hint.style=strToStyle(str.toLatin1());
|
|
}
|
|
else if(!(str=getEntry(ene, "bool", 2, "name", "hinting", "mode",
|
|
"assign")).isNull())
|
|
{
|
|
m_hinting.node=n;
|
|
m_hinting.set=str.toLower()!="false";
|
|
}
|
|
else if(!(str=getEntry(ene, "bool", 2, "name", "antialias", "mode",
|
|
"assign")).isNull())
|
|
{
|
|
m_antiAliasing.node=n;
|
|
m_antiAliasing.set=str.toLower()!="false";
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 3: // CPD: Is target "font" or "pattern" ????
|
|
if("font"==e.attribute("target"))
|
|
{
|
|
bool foundFalse=false;
|
|
QDomNode en=e.firstChild();
|
|
QString family;
|
|
double from=-1.0,
|
|
to=-1.0,
|
|
pixelFrom=-1.0,
|
|
pixelTo=-1.0;
|
|
|
|
while(!en.isNull())
|
|
{
|
|
QDomElement ene=en.toElement();
|
|
|
|
if(!ene.isNull())
|
|
{
|
|
if("test"==ene.tagName())
|
|
{
|
|
// kcmfonts used to write incorrectly more or less instead of
|
|
// more_eq and less_eq, so read both,
|
|
// first the old (wrong) one then the right one
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"size", "compare", "more")).isNull())
|
|
from=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"size", "compare", "more_eq")).isNull())
|
|
from=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"size", "compare", "less")).isNull())
|
|
to=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"size", "compare", "less_eq")).isNull())
|
|
to=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"pixelsize", "compare", "more")).isNull())
|
|
pixelFrom=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"pixelsize", "compare",
|
|
"more_eq")).isNull())
|
|
pixelFrom=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"pixelsize", "compare", "less")).isNull())
|
|
pixelTo=str.toDouble();
|
|
if(!(str=getEntry(ene, "double", 3, "qual", "any", "name",
|
|
"pixelsize", "compare",
|
|
"less_eq")).isNull())
|
|
pixelTo=str.toDouble();
|
|
}
|
|
else if("edit"==ene.tagName() &&
|
|
"false"==getEntry(ene, "bool", 2, "name", "antialias",
|
|
"mode", "assign"))
|
|
foundFalse=true;
|
|
}
|
|
|
|
en=en.nextSibling();
|
|
}
|
|
|
|
if((from>=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
|