summaryrefslogtreecommitdiffstats
path: root/kcontrol/kfontinst/lib
diff options
context:
space:
mode:
Diffstat (limited to 'kcontrol/kfontinst/lib')
-rw-r--r--kcontrol/kfontinst/lib/FcEngine.cpp1179
-rw-r--r--kcontrol/kfontinst/lib/FcEngine.h118
-rw-r--r--kcontrol/kfontinst/lib/KfiConstants.h73
-rw-r--r--kcontrol/kfontinst/lib/Makefile.am14
-rw-r--r--kcontrol/kfontinst/lib/Misc.cpp238
-rw-r--r--kcontrol/kfontinst/lib/Misc.h76
6 files changed, 1698 insertions, 0 deletions
diff --git a/kcontrol/kfontinst/lib/FcEngine.cpp b/kcontrol/kfontinst/lib/FcEngine.cpp
new file mode 100644
index 000000000..0b3e51767
--- /dev/null
+++ b/kcontrol/kfontinst/lib/FcEngine.cpp
@@ -0,0 +1,1179 @@
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qfontmetrics.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <kurl.h>
+#include <kconfig.h>
+#include <kglobalsettings.h>
+#include <kio/netaccess.h>
+#include <math.h>
+#include "FcEngine.h"
+#include "KfiConstants.h"
+#ifdef HAVE_XFT
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+#include <fixx11h.h>
+#endif
+
+#define KFI_HAVE_OBLIQUE // Do we differentiate between Italic and Oblique?
+#define KFI_HAVE_MEDIUM_WEIGHT // Do we differentiate between Medium and Normal weights?
+
+#define KFI_PREVIEW_GROUP "Preview Settings"
+#define KFI_PREVIEW_STRING_KEY "String"
+
+#ifdef HAVE_XFT
+#define KFI_DISPLAY(pix) (pix ? pix->x11Display() : QPaintDevice::x11AppDisplay())
+#endif
+
+namespace KFI
+{
+
+const int CFcEngine::constScalableSizes[]={8, 10, 12, 24, 36, 48, 64, 72, 96, 0 };
+const int CFcEngine::constDefaultAlphaSize=24;
+
+static int fcWeight(int weight)
+{
+ if(weight<FC_WEIGHT_ULTRALIGHT)
+ return FC_WEIGHT_THIN;
+
+ if(weight<(FC_WEIGHT_ULTRALIGHT+FC_WEIGHT_LIGHT)/2)
+ return FC_WEIGHT_ULTRALIGHT;
+
+ if(weight<(FC_WEIGHT_LIGHT+FC_WEIGHT_NORMAL)/2)
+ return FC_WEIGHT_LIGHT;
+
+#ifdef KFI_HAVE_MEDIUM_WEIGHT
+ if(weight<(FC_WEIGHT_NORMAL+FC_WEIGHT_MEDIUM)/2)
+ return FC_WEIGHT_NORMAL;
+
+ if(weight<(FC_WEIGHT_MEDIUM+FC_WEIGHT_SEMIBOLD)/2)
+ return FC_WEIGHT_MEDIUM;
+#else
+ if(weight<(FC_WEIGHT_NORMAL+FC_WEIGHT_SEMIBOLD)/2)
+ return FC_WEIGHT_NORMAL;
+#endif
+
+ if(weight<(FC_WEIGHT_SEMIBOLD+FC_WEIGHT_BOLD)/2)
+ return FC_WEIGHT_SEMIBOLD;
+
+ if(weight<(FC_WEIGHT_BOLD+FC_WEIGHT_ULTRABOLD)/2)
+ return FC_WEIGHT_BOLD;
+
+ if(weight<(FC_WEIGHT_ULTRABOLD+FC_WEIGHT_HEAVY)/2)
+ return FC_WEIGHT_ULTRABOLD;
+
+ return FC_WEIGHT_HEAVY;
+}
+
+static int fcToQtWeight(int weight)
+{
+ switch(weight)
+ {
+ case FC_WEIGHT_THIN:
+ return 0;
+ case FC_WEIGHT_ULTRALIGHT:
+ return QFont::Light>>1;
+ case FC_WEIGHT_LIGHT:
+ return QFont::Light;
+ default:
+ case FC_WEIGHT_NORMAL:
+ return QFont::Normal;
+ case FC_WEIGHT_MEDIUM:
+#ifdef KFI_HAVE_MEDIUM_WEIGHT
+ return (QFont::Normal+QFont::DemiBold)>>1;
+#endif
+ return QFont::Normal;
+ case FC_WEIGHT_SEMIBOLD:
+ return QFont::DemiBold;
+ case FC_WEIGHT_BOLD:
+ return QFont::Bold;
+ case FC_WEIGHT_ULTRABOLD:
+ return (QFont::Bold+QFont::Black)>>1;
+ case FC_WEIGHT_HEAVY:
+ return QFont::Black;
+ }
+}
+
+#ifndef KFI_FC_NO_WIDTHS
+static int fcWidth(int width)
+{
+ if(width<FC_WIDTH_EXTRACONDENSED)
+ return FC_WIDTH_ULTRACONDENSED;
+
+ if(width<(FC_WIDTH_EXTRACONDENSED+FC_WIDTH_CONDENSED)/2)
+ return FC_WIDTH_EXTRACONDENSED;
+
+ if(width<(FC_WIDTH_CONDENSED+FC_WIDTH_SEMICONDENSED)/2)
+ return FC_WIDTH_CONDENSED;
+
+ if(width<(FC_WIDTH_SEMICONDENSED+FC_WIDTH_NORMAL)/2)
+ return FC_WIDTH_SEMICONDENSED;
+
+ if(width<(FC_WIDTH_NORMAL+FC_WIDTH_SEMIEXPANDED)/2)
+ return FC_WIDTH_NORMAL;
+
+ if(width<(FC_WIDTH_SEMIEXPANDED+FC_WIDTH_EXPANDED)/2)
+ return FC_WIDTH_SEMIEXPANDED;
+
+ if(width<(FC_WIDTH_EXPANDED+FC_WIDTH_EXTRAEXPANDED)/2)
+ return FC_WIDTH_EXPANDED;
+
+ if(width<(FC_WIDTH_EXTRAEXPANDED+FC_WIDTH_ULTRAEXPANDED)/2)
+ return FC_WIDTH_EXTRAEXPANDED;
+
+ return FC_WIDTH_ULTRAEXPANDED;
+}
+
+static int fcToQtWidth(int weight)
+{
+ switch(weight)
+ {
+ case FC_WIDTH_ULTRACONDENSED:
+ return QFont::UltraCondensed;
+ case FC_WIDTH_EXTRACONDENSED:
+ return QFont::ExtraCondensed;
+ case FC_WIDTH_CONDENSED:
+ return QFont::Condensed;
+ case FC_WIDTH_SEMICONDENSED:
+ return QFont::SemiCondensed;
+ default:
+ case FC_WIDTH_NORMAL:
+ return QFont::Unstretched;
+ case FC_WIDTH_SEMIEXPANDED:
+ return QFont::SemiExpanded;
+ case FC_WIDTH_EXPANDED:
+ return QFont::Expanded;
+ case FC_WIDTH_EXTRAEXPANDED:
+ return QFont::ExtraExpanded;
+ case FC_WIDTH_ULTRAEXPANDED:
+ return QFont::UltraExpanded;
+ }
+}
+#endif
+
+static int fcSlant(int slant)
+{
+ if(slant<FC_SLANT_ITALIC)
+ return FC_SLANT_ROMAN;
+
+#ifdef KFI_HAVE_OBLIQUE
+ if(slant<(FC_SLANT_ITALIC+FC_SLANT_OBLIQUE)/2)
+ return FC_SLANT_ITALIC;
+
+ return FC_SLANT_OBLIQUE;
+#else
+ return FC_SLANT_ITALIC;
+#endif
+}
+
+static bool fcToQtSlant(int slant)
+{
+ return FC_SLANT_ROMAN==slant ? false : true;
+}
+
+static int fcSpacing(int spacing)
+{
+ if(spacing<FC_MONO)
+ return FC_PROPORTIONAL;
+
+ if(spacing<(FC_MONO+FC_CHARCELL)/2)
+ return FC_MONO;
+
+ return FC_CHARCELL;
+}
+
+static int strToWeight(const QString &str, QString &newStr)
+{
+ if(0==str.find(i18n(KFI_WEIGHT_THIN), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_THIN).length());
+ return FC_WEIGHT_THIN;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_EXTRALIGHT), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_EXTRALIGHT).length());
+ return FC_WEIGHT_EXTRALIGHT;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_ULTRALIGHT), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_ULTRALIGHT).length());
+ return FC_WEIGHT_ULTRALIGHT;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_LIGHT), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_LIGHT).length());
+ return FC_WEIGHT_LIGHT;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_REGULAR), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_REGULAR).length());
+ return FC_WEIGHT_REGULAR;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_NORMAL), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_NORMAL).length());
+ return FC_WEIGHT_NORMAL;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_MEDIUM), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_MEDIUM).length());
+ return FC_WEIGHT_MEDIUM;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_DEMIBOLD), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_DEMIBOLD).length());
+ return FC_WEIGHT_SEMIBOLD;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_SEMIBOLD), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_SEMIBOLD).length());
+ return FC_WEIGHT_SEMIBOLD;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_BOLD), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_BOLD).length());
+ return FC_WEIGHT_BOLD;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_EXTRABOLD), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_EXTRABOLD).length());
+ return FC_WEIGHT_EXTRABOLD;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_ULTRABOLD), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_ULTRABOLD).length());
+ return FC_WEIGHT_ULTRABOLD;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_BLACK), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_BLACK).length());
+ return FC_WEIGHT_BLACK;
+ }
+ if(0==str.find(i18n(KFI_WEIGHT_HEAVY), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WEIGHT_HEAVY).length());
+ return FC_WEIGHT_HEAVY;
+ }
+
+ newStr=str;
+ return FC_WEIGHT_REGULAR;
+}
+
+#ifndef KFI_FC_NO_WIDTHS
+static int strToWidth(const QString &str, QString &newStr)
+{
+ if(0==str.find(i18n(KFI_WIDTH_ULTRACONDENSED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_ULTRACONDENSED).length());
+ return FC_WIDTH_ULTRACONDENSED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_EXTRACONDENSED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_EXTRACONDENSED).length());
+ return FC_WIDTH_EXTRACONDENSED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_CONDENSED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_CONDENSED).length());
+ return FC_WIDTH_CONDENSED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_SEMICONDENSED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_SEMICONDENSED).length());
+ return FC_WIDTH_SEMICONDENSED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_NORMAL), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_NORMAL).length());
+ return FC_WIDTH_NORMAL;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_SEMIEXPANDED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_SEMIEXPANDED).length());
+ return FC_WIDTH_SEMIEXPANDED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_EXPANDED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_EXPANDED).length());
+ return FC_WIDTH_EXPANDED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_EXTRAEXPANDED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_EXTRAEXPANDED).length());
+ return FC_WIDTH_EXTRAEXPANDED;
+ }
+ if(0==str.find(i18n(KFI_WIDTH_ULTRAEXPANDED), 0, false))
+ {
+ newStr=str.mid(i18n(KFI_WIDTH_ULTRAEXPANDED).length());
+ return FC_WIDTH_ULTRAEXPANDED;
+ }
+
+ newStr=str;
+ return FC_WIDTH_NORMAL;
+}
+#endif
+
+static int strToSlant(const QString &str)
+{
+ if(-1!=str.find(i18n(KFI_SLANT_ITALIC)))
+ return FC_SLANT_ITALIC;
+ if(-1!=str.find(i18n(KFI_SLANT_OBLIQUE)))
+ return FC_SLANT_OBLIQUE;
+ return FC_SLANT_ROMAN;
+}
+
+static void drawText(QPainter &painter, int x, int y, int width, const QString &str)
+{
+ QString s(str);
+ bool addedElipses=false;
+
+ width-=x*2;
+ while(s.length()>3 && painter.fontMetrics().size(0, s).width()>width)
+ {
+ if(!addedElipses)
+ {
+ s.remove(s.length()-2, 2);
+ s.append("...");
+ addedElipses=true;
+ }
+ else
+ s.remove(s.length()-4, 1);
+ }
+ painter.drawText(x, y, s);
+}
+
+inline bool equal(double d1, double d2)
+{
+ return (fabs(d1 - d2) < 0.0001);
+}
+
+inline bool equalWeight(int a, int b)
+{
+ return a==b || fcWeight(a)==fcWeight(b);
+}
+
+#ifndef KFI_FC_NO_WIDTHS
+inline bool equalWidth(int a, int b)
+{
+ return a==b || fcWidth(a)==fcWidth(b);
+}
+#endif
+
+inline bool equalSlant(int a, int b)
+{
+ return a==b || fcSlant(a)==fcSlant(b);
+}
+
+#ifdef HAVE_XFT
+static bool drawChar(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const QString &text, int pos,
+ int &x, int &y, int w, int h, int fSize, int offset)
+{
+ XGlyphInfo extents;
+ const FcChar16 *str=(FcChar16 *)(&(text.ucs2()[pos]));
+
+ XftTextExtents16(pix.x11Display(), xftFont, str, 1, &extents);
+
+ if(x+extents.width+2>w)
+ {
+ x=offset;
+ y+=fSize;
+ }
+
+ if(y+offset<h)
+ {
+ XftDrawString16(xftDraw, xftCol, xftFont, x, y, str, 1);
+ x+=extents.width+2;
+ return true;
+ }
+ return false;
+}
+
+static bool drawString(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const QString &text,
+ int x, int &y, int h, int offset)
+{
+ XGlyphInfo extents;
+ const FcChar16 *str=(FcChar16 *)(text.ucs2());
+
+ XftTextExtents16(pix.x11Display(), xftFont, str, text.length(), &extents);
+ if(y+extents.height<h)
+ XftDrawString16(xftDraw, xftCol, xftFont, x, y+extents.y, str, text.length());
+ if(extents.height>0)
+ {
+ y+=extents.height+offset;
+ return true;
+ }
+ return false;
+}
+
+static bool drawGlyph(QPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, FT_UInt i,
+ int &x, int &y, int &w, int &h, int fSize, int offset)
+{
+ XGlyphInfo extents;
+
+ XftGlyphExtents(pix.x11Display(), xftFont, &i, 1, &extents);
+
+ if(x+extents.width+2>w)
+ {
+ x=offset;
+ y+=fSize;
+ }
+
+ if(y+offset<h)
+ {
+ XftDrawGlyphs(xftDraw, xftCol, xftFont, x, y, &i, 1);
+ x+=extents.width+2;
+ return true;
+ }
+ return false;
+}
+
+inline int point2Pixel(int point)
+{
+ return (point*QPaintDevice::x11AppDpiX()+36)/72;
+}
+
+static bool hasStr(XftFont *font, QString &str)
+{
+ unsigned int slen=str.length(),
+ ch;
+
+ for(ch=0; ch<slen; ++ch)
+ if(!FcCharSetHasChar(font->charset, str[ch].unicode()))
+ return false;
+ return true;
+}
+#endif
+
+CFcEngine::CFcEngine()
+ : itsIndex(-1),
+ itsIndexCount(1)
+{
+}
+
+CFcEngine::~CFcEngine()
+{
+ // Clear any fonts that may have been added...
+ FcConfigAppFontClear(FcConfigGetCurrent());
+}
+
+QString CFcEngine::getName(const KURL &url, int faceNo)
+{
+ if(url!=itsLastUrl || faceNo!=itsIndex)
+ parseUrl(url, faceNo);
+
+ return itsDescriptiveName;
+}
+
+#ifdef HAVE_XFT
+bool CFcEngine::draw(const KURL &url, int w, int h, QPixmap &pix, int faceNo, bool thumb)
+{
+ bool rv=false;
+
+ if((url==itsLastUrl && faceNo==itsIndex) || parseUrl(url, faceNo))
+ {
+ rv=true;
+
+ if(!itsInstalled) // Then add to fontconfig's list, so that Xft can display it...
+ {
+ FcInitReinitialize();
+ FcConfigAppFontAddFile(FcConfigGetCurrent(), (const FcChar8 *)(itsName.utf8().data()));
+ }
+
+ if(thumb && (w!=h || h>128))
+ thumb=false;
+
+ int offset=thumb
+ ? h<=32
+ ? 2
+ : 3
+ : 4,
+ x=offset, y=offset;
+
+ pix.resize(w, h);
+ pix.fill(Qt::white);
+
+ QPainter painter(&pix);
+
+ getSizes(&pix);
+
+ if(itsSizes.size())
+ {
+ XRenderColor xrenderCol;
+ XftColor xftCol;
+
+ xrenderCol.red=xrenderCol.green=xrenderCol.blue=0;
+ xrenderCol.alpha=0xffff;
+ XftColorAllocValue(pix.x11Display(), DefaultVisual(pix.x11Display(),
+ pix.x11Screen()),
+ DefaultColormap(pix.x11Display(), pix.x11Screen()),
+ &xrenderCol, &xftCol);
+
+ XftDraw *xftDraw=XftDrawCreate(pix.x11Display(), (Pixmap)(pix.handle()),
+ (Visual*)(pix.x11Visual()), pix.x11Colormap());
+
+ if(xftDraw)
+ {
+ XftFont *xftFont=NULL;
+ bool drawGlyphs=false;
+
+ if(thumb)
+ {
+ QString text(i18n("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789"));
+
+ //
+ // Calculate size of text...
+ int fSize= h <= 32
+ ? h-(offset*2) // 1 line of chars...
+ : h <= 64
+ ? (h-(offset*3))/2 // 2 lines...
+ : (h-(offset*4))/3; // 3 lines or more
+
+ if(!itsScalable) // Then need to get nearest size...
+ {
+ int bSize=fSize;
+
+ for(unsigned int s=0; s<itsSizes.size(); ++s)
+ if (itsSizes[s]<=fSize)
+ bSize=itsSizes[s];
+ fSize=bSize;
+ }
+
+ unsigned int ch;
+
+ xftFont=getFont(fSize, &pix);
+
+ y=fSize;
+ if(xftFont)
+ {
+ drawGlyphs=!hasStr(xftFont, text);
+
+ if(!drawGlyphs)
+ for(ch=0; ch<text.length(); ++ch) // Display char by char so that it wraps...
+ if(!drawChar(pix, xftDraw, xftFont, &xftCol, text, ch, x, y, w, h, fSize, offset))
+ break;
+ if(drawGlyphs)
+ {
+ FT_Face face=XftLockFace(xftFont);
+
+ if(face)
+ {
+ for(int i=1; i<face->num_glyphs && y<w; ++i) // Glyph 0 is the NULL glyph
+ if(!drawGlyph(pix, xftDraw, xftFont, &xftCol, i, x, y, w, h, fSize, offset))
+ break;
+
+ XftUnlockFace(xftFont);
+ }
+ }
+ }
+ }
+ else
+ {
+ QString lowercase(getLowercaseLetters()),
+ uppercase(getUppercaseLetters()),
+ punctuation(getPunctuation()),
+ title(itsDescriptiveName.isEmpty()
+ ? i18n("ERROR: Could not determine font's name.")
+ : itsDescriptiveName);
+
+ if(1==itsSizes.size())
+ title=i18n("%1 [1 pixel]", "%1 [%n pixels]", itsSizes[0]).arg(title);
+
+ painter.setFont(KGlobalSettings::generalFont());
+ painter.setPen(Qt::black);
+ y=painter.fontMetrics().height();
+ drawText(painter, x, y, w-offset, title);
+ y+=4;
+ painter.drawLine(offset, y, w-(offset+1), y);
+ y+=8;
+
+ bool lc=true,
+ uc=true,
+ punc=true;
+
+ xftFont=getFont(itsAlphaSize, &pix);
+ if(xftFont)
+ {
+ lc=hasStr(xftFont, lowercase);
+ uc=hasStr(xftFont, uppercase);
+ punc=hasStr(xftFont, punctuation);
+
+ drawGlyphs=!lc && !uc;
+
+ if(!drawGlyphs)
+ {
+ if(lc)
+ drawString(pix, xftDraw, xftFont, &xftCol, lowercase, x, y, h, offset);
+ if(uc)
+ drawString(pix, xftDraw, xftFont, &xftCol, uppercase, x, y, h, offset);
+ if(punc)
+ drawString(pix, xftDraw, xftFont, &xftCol, punctuation, x, y, h, offset);
+ XftFontClose(pix.x11Display(), xftFont);
+ if(lc || uc || punc)
+ painter.drawLine(offset, y, w-(offset+1), y);
+ y+=8;
+ }
+
+ QString previewString(getPreviewString());
+ bool stop=false;
+
+ if(!drawGlyphs)
+ {
+ if(!lc && uc)
+ previewString=previewString.upper();
+ if(!uc && lc)
+ previewString=previewString.lower();
+ }
+
+ for(unsigned int s=0; s<itsSizes.size(); ++s)
+ {
+ xftFont=getFont(itsSizes[s], &pix);
+
+ if(xftFont)
+ {
+ if(drawGlyphs)
+ {
+ FT_Face face=XftLockFace(xftFont);
+
+ if(face)
+ {
+ int space=itsSizes[s]/10;
+ XGlyphInfo extents;
+
+ if(!space)
+ space=1;
+
+ for(int i=1; i<face->num_glyphs && y<w && !stop; ++i)
+ {
+ XftGlyphExtents(pix.x11Display(), xftFont, (const FT_UInt *)&i, 1, &extents);
+
+ if(y+extents.height>h)
+ stop=true;
+ else
+ {
+ if(x+extents.width<w)
+ XftDrawGlyphs(xftDraw, &xftCol, xftFont, x, y+extents.y,
+ (const FT_UInt *)&i, 1);
+ if(extents.width>0)
+ x+=extents.width+space;
+ }
+ if(x>=w || i==face->num_glyphs-1)
+ {
+ y+=itsSizes[s]+offset;
+ x=offset;
+ break;
+ }
+ }
+
+ XftUnlockFace(xftFont);
+ }
+ }
+ else
+ drawString(pix, xftDraw, xftFont, &xftCol, previewString, x, y, h, offset);
+ XftFontClose(pix.x11Display(), xftFont);
+ }
+ }
+ }
+ }
+
+ XftDrawDestroy(xftDraw);
+ }
+ }
+ }
+
+ return rv;
+}
+#endif
+
+QString CFcEngine::getPreviewString()
+{
+ KConfig cfg(KFI_UI_CFG_FILE);
+
+ cfg.setGroup(KFI_PREVIEW_GROUP);
+
+ QString str(cfg.readEntry(KFI_PREVIEW_STRING_KEY));
+
+ return str.isEmpty() ? i18n("A sentence that uses all of the letters of the alphabet",
+ "The quick brown fox jumps over the lazy dog")
+ : str;
+}
+
+void CFcEngine::setPreviewString(const QString &str)
+{
+ KConfig cfg(KFI_UI_CFG_FILE);
+
+ cfg.setGroup(KFI_PREVIEW_GROUP);
+ cfg.writeEntry(KFI_PREVIEW_STRING_KEY, str);
+}
+
+QString CFcEngine::getUppercaseLetters()
+{
+ return i18n("All of the letters of the alphabet, uppercase", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+}
+
+QString CFcEngine::getLowercaseLetters()
+{
+ return i18n("All of the letters of the alphabet, lowercase", "abcdefghijklmnopqrstuvwxyz");
+}
+
+QString CFcEngine::getPunctuation()
+{
+ return i18n("Numbers and characters", "0123456789.:,;(*!?'/\\\")£$€%^&-+@~#<>{}[]");
+}
+
+QString CFcEngine::getFcString(FcPattern *pat, const char *val, int faceNo)
+{
+ QString rv;
+ FcChar8 *fcStr;
+
+ if(FcResultMatch==FcPatternGetString(pat, val, faceNo, &fcStr))
+ rv=QString::fromUtf8((char *)fcStr);
+
+ return rv;
+}
+
+QString CFcEngine::createName(FcPattern *pat, int faceNo)
+{
+//CPD: TODO: the names *need* to match up with kfontchooser's...
+ QString name(getFcString(pat, FC_FAMILY, faceNo)),
+ str;
+ int intVal;
+ bool comma=false;
+
+ if (FcResultMatch==FcPatternGetInteger(pat, FC_WEIGHT, faceNo, &intVal))
+ {
+ str=weightStr(intVal);
+ if(!str.isEmpty())
+ {
+ name+=QString(", ")+str;
+ comma=true;
+ }
+ }
+
+ if (FcResultMatch==FcPatternGetInteger(pat, FC_SLANT, faceNo, &intVal))
+ {
+ str=slantStr(intVal);
+ if(!str.isEmpty())
+ {
+ if(!comma)
+ {
+ name+=QChar(',');
+ comma=true;
+ }
+ name+=QChar(' ')+str;
+ }
+ }
+
+#ifndef KFI_FC_NO_WIDTHS
+ if (FcResultMatch==FcPatternGetInteger(pat, FC_WIDTH, faceNo, &intVal))
+ {
+ str=widthStr(intVal);
+ if(!str.isEmpty())
+ name+=QChar(' ')+str;
+ }
+#endif
+
+ return name;
+}
+
+QString CFcEngine::weightStr(int weight, bool emptyNormal)
+{
+ switch(fcWeight(weight))
+ {
+ case FC_WEIGHT_THIN:
+ return i18n(KFI_WEIGHT_THIN);
+ case FC_WEIGHT_ULTRALIGHT:
+ return i18n(KFI_WEIGHT_ULTRALIGHT);
+ case FC_WEIGHT_LIGHT:
+ return i18n(KFI_WEIGHT_LIGHT);
+ case FC_WEIGHT_NORMAL:
+ return emptyNormal ? QString::null : i18n(KFI_WEIGHT_NORMAL);
+ case FC_WEIGHT_MEDIUM:
+ return i18n(KFI_WEIGHT_MEDIUM);
+ case FC_WEIGHT_DEMIBOLD:
+ return i18n(KFI_WEIGHT_SEMIBOLD);
+ case FC_WEIGHT_BOLD:
+ return i18n(KFI_WEIGHT_BOLD);
+ case FC_WEIGHT_ULTRABOLD:
+ return i18n(KFI_WEIGHT_ULTRABOLD);
+ default:
+ return i18n(KFI_WEIGHT_HEAVY);
+ }
+}
+
+#ifndef KFI_FC_NO_WIDTHS
+QString CFcEngine::widthStr(int width, bool emptyNormal)
+{
+ switch(fcWidth(width))
+ {
+ case FC_WIDTH_ULTRACONDENSED:
+ return i18n(KFI_WIDTH_ULTRACONDENSED);
+ case FC_WIDTH_EXTRACONDENSED:
+ return i18n(KFI_WIDTH_EXTRACONDENSED);
+ case FC_WIDTH_CONDENSED:
+ return i18n(KFI_WIDTH_CONDENSED);
+ case FC_WIDTH_SEMICONDENSED:
+ return i18n(KFI_WIDTH_SEMICONDENSED);
+ case FC_WIDTH_NORMAL:
+ return emptyNormal ? QString::null : i18n(KFI_WIDTH_NORMAL);
+ case FC_WIDTH_SEMIEXPANDED:
+ return i18n(KFI_WIDTH_SEMIEXPANDED);
+ case FC_WIDTH_EXPANDED:
+ return i18n(KFI_WIDTH_EXPANDED);
+ case FC_WIDTH_EXTRAEXPANDED:
+ return i18n(KFI_WIDTH_EXTRAEXPANDED);
+ default:
+ return i18n(KFI_WIDTH_ULTRAEXPANDED);
+ }
+}
+#endif
+
+QString CFcEngine::slantStr(int slant, bool emptyNormal)
+{
+ switch(fcSlant(slant))
+ {
+ case FC_SLANT_OBLIQUE:
+ return i18n(KFI_SLANT_OBLIQUE);
+ case FC_SLANT_ITALIC:
+ return i18n(KFI_SLANT_ITALIC);
+ default:
+ return emptyNormal ? QString::null : i18n(KFI_SLANT_ROMAN);
+ }
+}
+
+QString CFcEngine::spacingStr(int spacing)
+{
+ switch(fcSpacing(spacing))
+ {
+ case FC_MONO:
+ return i18n(KFI_SPACING_MONO);
+ case FC_CHARCELL:
+ return i18n(KFI_SPACING_CHARCELL);
+ default:
+ return i18n(KFI_SPACING_PROPORTIONAL);
+ }
+}
+
+bool CFcEngine::getInfo(const KURL &url, int faceNo, QString &full, QString &family, QString &foundry, QString &weight,
+#ifndef KFI_FC_NO_WIDTHS
+ QString &width,
+#endif
+ QString &spacing, QString &slant)
+{
+ if(parseUrl(url, faceNo, true))
+ {
+ full=itsDescriptiveName;
+ if(url.isLocalFile())
+ {
+ int pos;
+
+ if(-1==(pos=itsDescriptiveName.find(", "))) // No style information...
+ family=itsDescriptiveName;
+ else
+ family=itsDescriptiveName.left(pos);
+ }
+ else
+ family=itsName;
+ weight=weightStr(itsWeight, false);
+#ifndef KFI_FC_NO_WIDTHS
+ width=widthStr(itsWidth, false);
+#endif
+ slant=slantStr(itsSlant, false);
+ spacing=spacingStr(itsSpacing);
+ foundry=itsFoundry;
+ return true;
+ }
+
+ return false;
+}
+
+QFont CFcEngine::getQFont(const QString &name, int size)
+{
+ parseName(name, 0, false);
+
+ QFont font(itsName, size, fcToQtWeight(itsWeight), fcToQtSlant(itsSlant));
+
+#ifndef KFI_FC_NO_WIDTHS
+ font.setStretch(fcToQtWidth(itsWidth));
+#endif
+ return font;
+}
+
+bool CFcEngine::parseUrl(const KURL &url, int faceNo, bool all)
+{
+ FcInitLoadConfigAndFonts();
+
+ // Possible urls:
+ //
+ // fonts:/times.ttf
+ // fonts:/System/times.ttf
+ // file:/home/wibble/hmm.ttf
+ //
+ if(KFI_KIO_FONTS_PROTOCOL==url.protocol())
+ {
+ KIO::UDSEntry udsEntry;
+ QString name;
+
+ FcInitReinitialize();
+ if(KIO::NetAccess::stat(url, udsEntry, NULL)) // Need to stat the url to get its font name...
+ {
+ KIO::UDSEntry::Iterator it(udsEntry.begin()),
+ end(udsEntry.end());
+
+ for( ; it != end; ++it)
+ if (KIO::UDS_NAME==(*it).m_uds)
+ {
+ name=(*it).m_str;
+ break;
+ }
+ }
+
+ if(!name.isEmpty())
+ {
+ parseName(name, faceNo, all);
+ itsInstalled=true;
+ }
+ else
+ return false;
+ }
+ else if(url.isLocalFile())
+ {
+ // Now lets see if its from the thumbnail job! if so, then file will just contain the URL!
+ QFile file(url.path());
+ bool isThumbnailUrl=false;
+
+ if(file.size()<2048 && file.open(IO_ReadOnly)) // Urls should be less than 2k, and fonts usually above!
+ {
+ QString thumbUrl;
+ QTextStream stream(&file);
+
+ thumbUrl=stream.readLine();
+ isThumbnailUrl=0==thumbUrl.find(KFI_KIO_FONTS_PROTOCOL) && parseUrl(KURL(thumbUrl), faceNo, all);
+ file.close();
+ }
+
+ if(!isThumbnailUrl) // Its not a thumbnail, so read the real font file...
+ {
+ itsName=url.path();
+
+ int count;
+ FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(itsName).data()), 0, NULL, &count);
+
+ itsWeight=FC_WEIGHT_NORMAL;
+#ifndef KFI_FC_NO_WIDTHS
+ itsWidth=FC_WIDTH_NORMAL;
+#endif
+ itsSlant=FC_SLANT_ROMAN;
+ itsSpacing=FC_PROPORTIONAL;
+
+ if(pat)
+ {
+ itsDescriptiveName=createName(pat, faceNo);
+
+ if(all)
+ {
+ FcPatternGetInteger(pat, FC_WEIGHT, faceNo, &itsWeight);
+ FcPatternGetInteger(pat, FC_SLANT, faceNo, &itsSlant);
+#ifndef KFI_FC_NO_WIDTHS
+ FcPatternGetInteger(pat, FC_WIDTH, faceNo, &itsWidth);
+#endif
+ FcPatternGetInteger(pat, FC_SPACING, faceNo, &itsSpacing);
+ itsFoundry=getFcString(pat, FC_FOUNDRY, faceNo);
+ }
+
+ FcPatternDestroy(pat);
+ }
+ else
+ itsDescriptiveName=QString::null;
+
+ itsInstalled=false;
+ itsIndex=faceNo;
+ }
+ }
+ else
+ return false;
+
+ itsLastUrl=url;
+ return true;
+}
+
+void CFcEngine::parseName(const QString &name, int faceNo, bool all)
+{
+ int pos;
+
+ itsDescriptiveName=name;
+ itsSpacing=FC_PROPORTIONAL;
+ if(-1==(pos=name.find(", "))) // No style information...
+ {
+ itsWeight=FC_WEIGHT_NORMAL;
+#ifndef KFI_FC_NO_WIDTHS
+ itsWidth=FC_WIDTH_NORMAL;
+#endif
+ itsSlant=FC_SLANT_ROMAN;
+ itsName=name;
+ }
+ else
+ {
+ QString style(name.mid(pos+2));
+
+ itsWeight=strToWeight(style, style);
+#ifndef KFI_FC_NO_WIDTHS
+ itsWidth=strToWidth(style, style);
+#endif
+ itsSlant=strToSlant(style);
+ itsName=name.left(pos);
+ }
+
+ if(all)
+ {
+ FcObjectSet *os = FcObjectSetBuild(FC_SPACING, FC_FOUNDRY, (void *)0);
+ FcPattern *pat = FcPatternBuild(NULL,
+ FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.utf8().data()),
+ FC_WEIGHT, FcTypeInteger, itsWeight,
+ FC_SLANT, FcTypeInteger, itsSlant,
+#ifndef KFI_FC_NO_WIDTHS
+ FC_WIDTH, FcTypeInteger, itsWidth,
+#endif
+ NULL);
+ FcFontSet *set = FcFontList(0, pat, os);
+
+ FcPatternDestroy(pat);
+ FcObjectSetDestroy(os);
+
+ if(set && set->nfont)
+ {
+ FcPatternGetInteger(set->fonts[0], FC_SPACING, faceNo, &itsSpacing);
+ itsFoundry=getFcString(set->fonts[0], FC_FOUNDRY, faceNo);
+ }
+ }
+
+ itsIndex=0; // Doesn't matter, as we're gonna use font name!
+ itsLastUrl=KURL();
+}
+
+#ifdef HAVE_XFT
+XftFont * CFcEngine::getFont(int size, QPixmap *pix)
+{
+ if(itsInstalled)
+ return XftFontOpen(KFI_DISPLAY(pix), 0,
+ FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.utf8().data()),
+ FC_WEIGHT, FcTypeInteger, itsWeight,
+ FC_SLANT, FcTypeInteger, itsSlant,
+#ifndef KFI_FC_NO_WIDTHS
+ FC_WIDTH, FcTypeInteger, itsWidth,
+#endif
+ FC_PIXEL_SIZE, FcTypeDouble, (double)size,
+ NULL);
+ else
+ {
+ FcPattern *pattern = FcPatternBuild(NULL,
+ FC_FILE, FcTypeString, QFile::encodeName(itsName).data(),
+ FC_INDEX, FcTypeInteger, itsIndex,
+ FC_PIXEL_SIZE, FcTypeDouble, (double)size,
+ NULL);
+ return XftFontOpenPattern(KFI_DISPLAY(pix), pattern);
+ }
+}
+
+void CFcEngine::getSizes(QPixmap *pix)
+{
+ static const int constNumSizes=11;
+ static const int constNumSizeRanges=2;
+ static const int constSizes[constNumSizeRanges][constNumSizes]= { {8, 10, 12, 14, 16, 18, 24, 36, 48, 72, 96},
+ {7, 9, 11, 13, 15, 17, 23, 35, 47, 71, 95} };
+ XftFont *f=getFont(8, pix);
+
+ itsScalable=FcTrue;
+
+ itsSizes.clear();
+ itsAlphaSize=0;
+
+ if(f)
+ {
+ bool gotSizes=false;
+
+ if(itsInstalled)
+ {
+ if(FcResultMatch!=FcPatternGetBool(f->pattern, FC_SCALABLE, 0, &itsScalable))
+ itsScalable=FcFalse;
+ }
+ else
+ {
+ FT_Face face=XftLockFace(f);
+
+ if(face)
+ {
+ itsIndexCount=face->num_faces;
+ if(!(itsScalable=FT_IS_SCALABLE(face)))
+ {
+ int numSizes=face->num_fixed_sizes,
+ size;
+
+ gotSizes=true;
+
+ itsSizes.reserve(numSizes);
+
+ for (size=0; size<numSizes; size++)
+ {
+ itsSizes.push_back(face->available_sizes[size].height);
+ if (face->available_sizes[size].height<=constDefaultAlphaSize)
+ itsAlphaSize=face->available_sizes[size].height;
+ }
+ }
+ XftUnlockFace(f);
+ }
+ }
+
+ XftFontClose(KFI_DISPLAY(pix), f);
+
+ //
+ // Hmm... its not a scalable font, and its installed. So to get list of sizes, iterate through a list of standard
+ // sizes, and ask fontconfig for a font of that sizes. Then check the retured size, family, etc is what was asked
+ // for!
+ if(!itsScalable && !gotSizes)
+ {
+ itsSizes.reserve(constNumSizes);
+
+ for(int l=0; l<constNumSizeRanges && !gotSizes; ++l)
+ for(int i=0; i<constNumSizes; ++i)
+ {
+ double px;
+ int iv;
+ FcChar8 *str;
+
+ f=getFont(constSizes[l][i], pix);
+
+ if(f)
+ {
+ if(FcResultMatch==FcPatternGetDouble(f->pattern, FC_PIXEL_SIZE, 0, &px) && equal(constSizes[l][i], px) &&
+ FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv) && equalWeight(iv,itsWeight) &&
+ FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv) && equalSlant(iv, itsSlant) &&
+#ifndef KFI_FC_NO_WIDTHS
+ FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv) && equalWidth(iv, itsWidth) &&
+#endif
+ FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str &&
+ QString::fromUtf8((char *)str)==itsName)
+ {
+ itsSizes.push_back(constSizes[l][i]);
+ gotSizes=true;
+ if(constSizes[l][i]<=constDefaultAlphaSize)
+ itsAlphaSize=constSizes[l][i];
+ }
+ XftFontClose(KFI_DISPLAY(pix), f);
+ }
+ }
+ }
+ }
+
+ if(itsScalable)
+ {
+ itsSizes.reserve(constNumSizes);
+
+ for (int i=0; constScalableSizes[i]; ++i)
+ itsSizes.push_back(point2Pixel(constScalableSizes[i]));
+ itsAlphaSize=constDefaultAlphaSize;
+ }
+}
+#endif
+
+}
diff --git a/kcontrol/kfontinst/lib/FcEngine.h b/kcontrol/kfontinst/lib/FcEngine.h
new file mode 100644
index 000000000..4a09b8a55
--- /dev/null
+++ b/kcontrol/kfontinst/lib/FcEngine.h
@@ -0,0 +1,118 @@
+#ifndef __FC_ENGINE_H__
+#define __FC_ENGINE_H__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <qstring.h>
+#include <qvaluevector.h>
+#include <qfont.h>
+#include <kurl.h>
+#include <kdeversion.h>
+#include <fontconfig/fontconfig.h>
+
+#if (FC_VERSION<20200)
+
+#define KFI_FC_NO_WIDTHS
+#define KFI_FC_LIMITED_WEIGHTS
+
+#endif
+
+#ifdef KFI_FC_LIMITED_WEIGHTS
+
+#undef FC_WEIGHT_LIGHT
+#define FC_WEIGHT_THIN 0
+#define FC_WEIGHT_EXTRALIGHT 40
+#define FC_WEIGHT_ULTRALIGHT FC_WEIGHT_EXTRALIGHT
+#define FC_WEIGHT_LIGHT 50
+#define FC_WEIGHT_BOOK 75
+#define FC_WEIGHT_REGULAR 80
+#define FC_WEIGHT_NORMAL FC_WEIGHT_REGULAR
+#define FC_WEIGHT_SEMIBOLD FC_WEIGHT_DEMIBOLD
+#define FC_WEIGHT_EXTRABOLD 205
+#define FC_WEIGHT_ULTRABOLD FC_WEIGHT_EXTRABOLD
+#define FC_WEIGHT_HEAVY FC_WEIGHT_BLACK
+
+#endif
+
+class QPixmap;
+
+#ifdef HAVE_XFT
+typedef struct _XftFont XftFont;
+#endif
+
+namespace KFI
+{
+
+class KDE_EXPORT CFcEngine
+{
+ public:
+
+ CFcEngine();
+ ~CFcEngine();
+
+#ifdef HAVE_XFT
+ bool draw(const KURL &url, int w, int h, QPixmap &pix, int faceNo, bool thumb);
+#endif
+ int getNumIndexes() { return itsIndexCount; } // Only valid after draw has been called!
+ QString getName(const KURL &url, int faceNo=0);
+ bool getInfo(const KURL &url, int faceNo, QString &full, QString &family, QString &foundry, QString &weight,
+#ifndef KFI_FC_NO_WIDTHS
+ QString &width,
+#endif
+ QString &spacing, QString &slant);
+ QFont getQFont(const QString &name, int size);
+
+ const QValueVector<int> & sizes() const { return itsSizes; }
+ int alphaSize() const { return itsAlphaSize; }
+
+ static QString getPreviewString();
+ static void setPreviewString(const QString &str);
+ static QString getUppercaseLetters();
+ static QString getLowercaseLetters();
+ static QString getPunctuation();
+ static QString getFcString(FcPattern *pat, const char *val, int faceNo=0);
+ static QString createName(FcPattern *pat, int faceNo=0);
+ static QString weightStr(int weight, bool emptyNormal=true);
+#ifndef KFI_FC_NO_WIDTHS
+ static QString widthStr(int width, bool emptyNormal=true);
+#endif
+ static QString slantStr(int slant, bool emptyNormal=true);
+ static QString spacingStr(int spacing);
+
+ static const int constScalableSizes[];
+ static const int constDefaultAlphaSize;
+
+ private:
+
+ bool parseUrl(const KURL &url, int faceNo, bool all=false);
+ void parseName(const QString &name, int faceNo, bool all=false);
+#ifdef HAVE_XFT
+ XftFont * getFont(int size, QPixmap *pix=NULL);
+ void getSizes(QPixmap *pix=NULL);
+#endif
+
+ private:
+
+ bool itsInstalled;
+ QString itsName,
+ itsDescriptiveName,
+ itsFoundry;
+ int itsIndex,
+ itsIndexCount,
+ itsWeight,
+#ifndef KFI_FC_NO_WIDTHS
+ itsWidth,
+#endif
+ itsSlant,
+ itsSpacing,
+ itsAlphaSize;
+ QValueVector<int> itsSizes;
+ KURL itsLastUrl;
+ FcBool itsScalable;
+};
+
+}
+
+#endif
diff --git a/kcontrol/kfontinst/lib/KfiConstants.h b/kcontrol/kfontinst/lib/KfiConstants.h
new file mode 100644
index 000000000..fa7f6f1a0
--- /dev/null
+++ b/kcontrol/kfontinst/lib/KfiConstants.h
@@ -0,0 +1,73 @@
+#ifndef __KFI_CONSTANTS_H__
+#define __KFI_CONSTANTS_H__
+
+#include <klocale.h>
+
+#define KFI_CATALOGUE "kfontinst"
+
+// io-slave
+#define KFI_KIO_FONTS_PROTOCOL "fonts"
+#define KFI_KIO_FONTS_USER I18N_NOOP("Personal")
+#define KFI_KIO_FONTS_SYS I18N_NOOP("System")
+#define KFI_KIO_NO_CLEAR "?noclear"
+
+// Config
+#define KFI_UI_CFG_FILE KFI_CATALOGUE"uirc"
+#define KFI_CFG_FILE KFI_CATALOGUE"rc"
+#define KFI_ROOT_CFG_DIR "/etc/fonts/"
+#define KFI_ROOT_CFG_FILE KFI_ROOT_CFG_DIR KFI_CFG_FILE
+#define KFI_CFG_X_KEY "ConfigureX"
+#define KFI_CFG_GS_KEY "ConfigureGS"
+#define KFI_DEFAULT_CFG_X true
+#define KFI_DEFAULT_CFG_GS false
+
+// KIO::special
+
+namespace KFI
+{
+
+enum ESpecial
+{
+ SPECIAL_RECONFIG = 0,
+ SPECIAL_RESCAN = 1
+};
+
+}
+
+// Font name...
+#define KFI_WEIGHT_THIN I18N_NOOP("Thin")
+#define KFI_WEIGHT_EXTRALIGHT I18N_NOOP("ExtraLight")
+#define KFI_WEIGHT_ULTRALIGHT I18N_NOOP("UltraLight")
+#define KFI_WEIGHT_LIGHT I18N_NOOP("Light")
+#define KFI_WEIGHT_REGULAR I18N_NOOP("Regular")
+#define KFI_WEIGHT_NORMAL I18N_NOOP("Normal")
+#define KFI_WEIGHT_MEDIUM I18N_NOOP("Medium")
+#define KFI_WEIGHT_DEMIBOLD I18N_NOOP("DemiBold")
+#define KFI_WEIGHT_SEMIBOLD I18N_NOOP("SemiBold")
+#define KFI_WEIGHT_BOLD I18N_NOOP("Bold")
+#define KFI_WEIGHT_EXTRABOLD I18N_NOOP("ExtraBold")
+#define KFI_WEIGHT_ULTRABOLD I18N_NOOP("UltraBold")
+#define KFI_WEIGHT_BLACK I18N_NOOP("Black")
+#define KFI_WEIGHT_HEAVY I18N_NOOP("Heavy")
+
+#define KFI_SLANT_ROMAN I18N_NOOP("Roman")
+#define KFI_SLANT_ITALIC I18N_NOOP("Italic")
+#define KFI_SLANT_OBLIQUE I18N_NOOP("Oblique")
+
+#define KFI_WIDTH_ULTRACONDENSED I18N_NOOP("UltraCondensed")
+#define KFI_WIDTH_EXTRACONDENSED I18N_NOOP("ExtraCondensed")
+#define KFI_WIDTH_CONDENSED I18N_NOOP("Condensed")
+#define KFI_WIDTH_SEMICONDENSED I18N_NOOP("SemiCondensed")
+#define KFI_WIDTH_NORMAL I18N_NOOP("Normal")
+#define KFI_WIDTH_SEMIEXPANDED I18N_NOOP("SemiExpanded")
+#define KFI_WIDTH_EXPANDED I18N_NOOP("Expanded")
+#define KFI_WIDTH_EXTRAEXPANDED I18N_NOOP("ExtraExpanded")
+#define KFI_WIDTH_ULTRAEXPANDED I18N_NOOP("UltraExpanded")
+
+#define KFI_SPACING_MONO I18N_NOOP("Monospaced")
+#define KFI_SPACING_CHARCELL I18N_NOOP("Charcell")
+#define KFI_SPACING_PROPORTIONAL I18N_NOOP("Proportional")
+
+#define KFI_UNKNOWN_FOUNDRY I18N_NOOP("Unknown")
+
+#endif
diff --git a/kcontrol/kfontinst/lib/Makefile.am b/kcontrol/kfontinst/lib/Makefile.am
new file mode 100644
index 000000000..55349b149
--- /dev/null
+++ b/kcontrol/kfontinst/lib/Makefile.am
@@ -0,0 +1,14 @@
+lib_LTLIBRARIES = libkfontinst.la
+
+libkfontinst_la_SOURCES = \
+Misc.cpp \
+FcEngine.cpp
+
+noinst_HEADERS = \
+Misc.h \
+FcEngine.h \
+KfiConstants.h
+
+libkfontinst_la_LIBADD = $(LIB_KDECORE) $(LIBFONTCONFIG_LIBS) $(LIBFREETYPE_LIBS) $(LIB_KIO) $(LIBXFT_LIB)
+libkfontinst_la_LDFLAGS = $(all_libraries) $(KDE_RPATH) $(LIBFONTCONFIG_RPATH) $(LIBFREETYPE_RPATH) -no-undefined
+AM_CPPFLAGS= $(all_includes) $(LIBFREETYPE_CFLAGS) $(LIBFONTCONFIG_CFLAGS) -D_LARGEFILE64_SOURCE
diff --git a/kcontrol/kfontinst/lib/Misc.cpp b/kcontrol/kfontinst/lib/Misc.cpp
new file mode 100644
index 000000000..4606ad0ca
--- /dev/null
+++ b/kcontrol/kfontinst/lib/Misc.cpp
@@ -0,0 +1,238 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Namespace : KFI::Misc
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 01/05/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003, 2004
+////////////////////////////////////////////////////////////////////////////////
+
+#include "Misc.h"
+#include <qfile.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <klargefile.h>
+#include <kio/netaccess.h>
+#include <unistd.h>
+
+namespace KFI
+{
+
+namespace Misc
+{
+
+QString linkedTo(const QString &i)
+{
+ QString d;
+
+ if(isLink(i))
+ {
+ char buffer[1000];
+ int n=readlink(QFile::encodeName(i), buffer, 1000);
+
+ if(n!=-1)
+ {
+ buffer[n]='\0';
+ d=buffer;
+ }
+ }
+
+ return d;
+}
+
+QString dirSyntax(const QString &d)
+{
+ if(!d.isEmpty())
+ {
+ QString ds(d);
+
+ ds.replace("//", "/");
+
+ int slashPos=ds.findRev('/');
+
+ if(slashPos!=(((int)ds.length())-1))
+ ds.append('/');
+
+ return ds;
+ }
+
+ return d;
+}
+
+QString xDirSyntax(const QString &d)
+{
+ if(!d.isEmpty())
+ {
+ QString ds(d);
+
+ ds.replace("//", "/");
+
+ int slashPos=ds.findRev('/');
+
+ if(slashPos==(((int)ds.length())-1))
+ ds.remove(slashPos, 1);
+ return ds;
+ }
+
+ return d;
+}
+
+QString getDir(const QString &f)
+{
+ QString d(f);
+
+ int slashPos=d.findRev('/');
+
+ if(slashPos!=-1)
+ d.remove(slashPos+1, d.length());
+
+ return dirSyntax(d);
+}
+
+QString getFile(const QString &f)
+{
+ QString d(f);
+
+ int slashPos=d.findRev('/');
+
+ if(slashPos!=-1)
+ d.remove(0, slashPos+1);
+
+ return d;
+}
+
+bool createDir(const QString &dir)
+{
+ //
+ // Clear any umask before dir is created
+ mode_t oldMask=umask(0000);
+ bool status=KStandardDirs::makeDir(dir, DIR_PERMS);
+ // Reset umask
+ ::umask(oldMask);
+ return status;
+}
+
+bool doCmd(const QString &cmd, const QString &p1, const QString &p2, const QString &p3)
+{
+ KProcess proc;
+
+ proc << cmd;
+
+ if(!p1.isEmpty())
+ proc << p1;
+ if(!p2.isEmpty())
+ proc << p2;
+ if(!p3.isEmpty())
+ proc << p3;
+
+ proc.start(KProcess::Block);
+
+ return proc.normalExit() && proc.exitStatus()==0;
+}
+
+QString changeExt(const QString &f, const QString &newExt)
+{
+ QString newStr(f);
+ int dotPos=newStr.findRev('.');
+
+ if(-1==dotPos)
+ newStr+=QChar('.')+newExt;
+ else
+ {
+ newStr.remove(dotPos+1, newStr.length());
+ newStr+=newExt;
+ }
+ return newStr;
+}
+
+void createBackup(const QString &f)
+{
+ const QString constExt(".bak");
+
+ if(!fExists(f+constExt) && fExists(f))
+ doCmd("cp", "-f", f, f+constExt);
+}
+
+//
+// Get a list of files associated with a file, e.g.:
+//
+// File: /home/a/courier.pfa
+//
+// Associated: /home/a/courier.afm /home/a/courier.pfm
+//
+void getAssociatedUrls(const KURL &url, KURL::List &list, bool afmAndPfm, QWidget *widget)
+{
+ const char *afm[]={"afm", "AFM", "Afm", "AFm", "AfM", "aFM", "aFm", "afM", NULL},
+ *pfm[]={"pfm", "PFM", "Pfm", "PFm", "PfM", "pFM", "pFm", "pfM", NULL};
+ bool gotAfm=false,
+ localFile=url.isLocalFile();
+ int e;
+
+ for(e=0; afm[e]; ++e)
+ {
+ KURL statUrl(url);
+ KIO::UDSEntry uds;
+
+ statUrl.setPath(changeExt(url.path(), afm[e]));
+
+ if(localFile ? fExists(statUrl.path()) : KIO::NetAccess::stat(statUrl, uds, widget))
+ {
+ list.append(statUrl);
+ gotAfm=true;
+ break;
+ }
+ }
+
+ if(afmAndPfm || !gotAfm)
+ for(e=0; pfm[e]; ++e)
+ {
+ KURL statUrl(url);
+ KIO::UDSEntry uds;
+
+ statUrl.setPath(changeExt(url.path(), pfm[e]));
+ if(localFile ? fExists(statUrl.path()) : KIO::NetAccess::stat(statUrl, uds, widget))
+ {
+ list.append(statUrl);
+ break;
+ }
+ }
+}
+
+time_t getTimeStamp(const QString &item)
+{
+ KDE_struct_stat info;
+
+ return !item.isEmpty() && 0==KDE_lstat(QFile::encodeName(item), &info) ? info.st_mtime : 0;
+}
+
+
+bool check(const QString &path, unsigned int fmt, bool checkW)
+{
+ KDE_struct_stat info;
+ QCString pathC(QFile::encodeName(path));
+
+ return 0==KDE_lstat(pathC, &info) && (info.st_mode&S_IFMT)==fmt && (!checkW || 0==::access(pathC, W_OK));
+}
+
+}
+
+}
diff --git a/kcontrol/kfontinst/lib/Misc.h b/kcontrol/kfontinst/lib/Misc.h
new file mode 100644
index 000000000..a624f44f9
--- /dev/null
+++ b/kcontrol/kfontinst/lib/Misc.h
@@ -0,0 +1,76 @@
+#ifndef __MISC_H__
+#define __MISC_H__
+
+////////////////////////////////////////////////////////////////////////////////
+//
+// Namespace : KFI::Misc
+// Author : Craig Drummond
+// Project : K Font Installer
+// Creation Date : 01/05/2001
+// Version : $Revision$ $Date$
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+////////////////////////////////////////////////////////////////////////////////
+// (C) Craig Drummond, 2001, 2002, 2003
+////////////////////////////////////////////////////////////////////////////////
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kurl.h>
+
+class QWidget;
+
+namespace KFI
+{
+
+namespace Misc
+{
+ enum EConstants
+ {
+ FILE_PERMS = 0644,
+ DIR_PERMS = 0755
+ };
+
+ extern KDE_EXPORT bool check(const QString &path, unsigned int fmt, bool checkW=false);
+ inline KDE_EXPORT bool fExists(const QString &p) { return check(p, S_IFREG, false); }
+ inline KDE_EXPORT bool dExists(const QString &p) { return check(p, S_IFDIR, false); }
+ inline KDE_EXPORT bool fWritable(const QString &p) { return check(p, S_IFREG, true); }
+ inline KDE_EXPORT bool dWritable(const QString &p) { return check(p, S_IFDIR, true); }
+ inline KDE_EXPORT bool isLink(const QString &i) { return check(i, S_IFLNK, false); }
+ extern KDE_EXPORT QString linkedTo(const QString &i);
+ extern KDE_EXPORT QString dirSyntax(const QString &d); // Has trailing slash: /file/path/
+ extern KDE_EXPORT QString xDirSyntax(const QString &d); // No trailing slash: /file/path
+ inline KDE_EXPORT QString fileSyntax(const QString &f) { return xDirSyntax(f); }
+ extern KDE_EXPORT QString getDir(const QString &f);
+ extern KDE_EXPORT QString getFile(const QString &f);
+ extern KDE_EXPORT bool createDir(const QString &dir);
+ extern KDE_EXPORT QString changeExt(const QString &f, const QString &newExt);
+ extern KDE_EXPORT bool doCmd(const QString &cmd, const QString &p1=QString::null, const QString &p2=QString::null, const QString &p3=QString::null);
+ inline KDE_EXPORT bool root() { return 0==getuid(); }
+ extern KDE_EXPORT void getAssociatedUrls(const KURL &url, KURL::List &list, bool afmAndPfm=true, QWidget *widget=NULL);
+ extern KDE_EXPORT void createBackup(const QString &f);
+ extern KDE_EXPORT time_t getTimeStamp(const QString &item);
+}
+
+}
+
+#endif