You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1180 lines
35 KiB
1180 lines
35 KiB
#include <tqpainter.h>
|
|
#include <tqpixmap.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <tqfile.h>
|
|
#include <tqtextstream.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() : TQPaintDevice::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 TQFont::Light>>1;
|
|
case FC_WEIGHT_LIGHT:
|
|
return TQFont::Light;
|
|
default:
|
|
case FC_WEIGHT_NORMAL:
|
|
return TQFont::Normal;
|
|
case FC_WEIGHT_MEDIUM:
|
|
#ifdef KFI_HAVE_MEDIUM_WEIGHT
|
|
return (TQFont::Normal+TQFont::DemiBold)>>1;
|
|
#endif
|
|
return TQFont::Normal;
|
|
case FC_WEIGHT_SEMIBOLD:
|
|
return TQFont::DemiBold;
|
|
case FC_WEIGHT_BOLD:
|
|
return TQFont::Bold;
|
|
case FC_WEIGHT_ULTRABOLD:
|
|
return (TQFont::Bold+TQFont::Black)>>1;
|
|
case FC_WEIGHT_HEAVY:
|
|
return TQFont::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 TQFont::UltraCondensed;
|
|
case FC_WIDTH_EXTRACONDENSED:
|
|
return TQFont::ExtraCondensed;
|
|
case FC_WIDTH_CONDENSED:
|
|
return TQFont::Condensed;
|
|
case FC_WIDTH_SEMICONDENSED:
|
|
return TQFont::SemiCondensed;
|
|
default:
|
|
case FC_WIDTH_NORMAL:
|
|
return TQFont::Unstretched;
|
|
case FC_WIDTH_SEMIEXPANDED:
|
|
return TQFont::SemiExpanded;
|
|
case FC_WIDTH_EXPANDED:
|
|
return TQFont::Expanded;
|
|
case FC_WIDTH_EXTRAEXPANDED:
|
|
return TQFont::ExtraExpanded;
|
|
case FC_WIDTH_ULTRAEXPANDED:
|
|
return TQFont::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 TQString &str, TQString &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 TQString &str, TQString &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 TQString &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(TQPainter &painter, int x, int y, int width, const TQString &str)
|
|
{
|
|
TQString 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(TQPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const TQString &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(TQPixmap &pix, XftDraw *xftDraw, XftFont *xftFont, XftColor *xftCol, const TQString &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(TQPixmap &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*TQPaintDevice::x11AppDpiX()+36)/72;
|
|
}
|
|
|
|
static bool hasStr(XftFont *font, TQString &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());
|
|
}
|
|
|
|
TQString 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, TQPixmap &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);
|
|
|
|
TQPainter 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)
|
|
{
|
|
TQString 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
|
|
{
|
|
TQString 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;
|
|
}
|
|
|
|
TQString 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
|
|
|
|
TQString CFcEngine::getPreviewString()
|
|
{
|
|
KConfig cfg(KFI_UI_CFG_FILE);
|
|
|
|
cfg.setGroup(KFI_PREVIEW_GROUP);
|
|
|
|
TQString 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 TQString &str)
|
|
{
|
|
KConfig cfg(KFI_UI_CFG_FILE);
|
|
|
|
cfg.setGroup(KFI_PREVIEW_GROUP);
|
|
cfg.writeEntry(KFI_PREVIEW_STRING_KEY, str);
|
|
}
|
|
|
|
TQString CFcEngine::getUppercaseLetters()
|
|
{
|
|
return i18n("All of the letters of the alphabet, uppercase", "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
}
|
|
|
|
TQString CFcEngine::getLowercaseLetters()
|
|
{
|
|
return i18n("All of the letters of the alphabet, lowercase", "abcdefghijklmnopqrstuvwxyz");
|
|
}
|
|
|
|
TQString CFcEngine::getPunctuation()
|
|
{
|
|
return i18n("Numbers and characters", "0123456789.:,;(*!?'/\\\")£$€%^&-+@~#<>{}[]");
|
|
}
|
|
|
|
TQString CFcEngine::getFcString(FcPattern *pat, const char *val, int faceNo)
|
|
{
|
|
TQString rv;
|
|
FcChar8 *fcStr;
|
|
|
|
if(FcResultMatch==FcPatternGetString(pat, val, faceNo, &fcStr))
|
|
rv=TQString::fromUtf8((char *)fcStr);
|
|
|
|
return rv;
|
|
}
|
|
|
|
TQString CFcEngine::createName(FcPattern *pat, int faceNo)
|
|
{
|
|
//CPD: TODO: the names *need* to match up with kfontchooser's...
|
|
TQString 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+=TQString(", ")+str;
|
|
comma=true;
|
|
}
|
|
}
|
|
|
|
if (FcResultMatch==FcPatternGetInteger(pat, FC_SLANT, faceNo, &intVal))
|
|
{
|
|
str=slantStr(intVal);
|
|
if(!str.isEmpty())
|
|
{
|
|
if(!comma)
|
|
{
|
|
name+=TQChar(',');
|
|
comma=true;
|
|
}
|
|
name+=TQChar(' ')+str;
|
|
}
|
|
}
|
|
|
|
#ifndef KFI_FC_NO_WIDTHS
|
|
if (FcResultMatch==FcPatternGetInteger(pat, FC_WIDTH, faceNo, &intVal))
|
|
{
|
|
str=widthStr(intVal);
|
|
if(!str.isEmpty())
|
|
name+=TQChar(' ')+str;
|
|
}
|
|
#endif
|
|
|
|
return name;
|
|
}
|
|
|
|
TQString 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 ? TQString::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
|
|
TQString 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 ? TQString::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
|
|
|
|
TQString 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 ? TQString::null : i18n(KFI_SLANT_ROMAN);
|
|
}
|
|
}
|
|
|
|
TQString 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, TQString &full, TQString &family, TQString &foundry, TQString &weight,
|
|
#ifndef KFI_FC_NO_WIDTHS
|
|
TQString &width,
|
|
#endif
|
|
TQString &spacing, TQString &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;
|
|
}
|
|
|
|
TQFont CFcEngine::getQFont(const TQString &name, int size)
|
|
{
|
|
parseName(name, 0, false);
|
|
|
|
TQFont 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;
|
|
TQString 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!
|
|
TQFile file(url.path());
|
|
bool isThumbnailUrl=false;
|
|
|
|
if(file.size()<2048 && file.open(IO_ReadOnly)) // Urls should be less than 2k, and fonts usually above!
|
|
{
|
|
TQString thumbUrl;
|
|
TQTextStream 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 *)(TQFile::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=TQString::null;
|
|
|
|
itsInstalled=false;
|
|
itsIndex=faceNo;
|
|
}
|
|
}
|
|
else
|
|
return false;
|
|
|
|
itsLastUrl=url;
|
|
return true;
|
|
}
|
|
|
|
void CFcEngine::parseName(const TQString &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
|
|
{
|
|
TQString 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, TQPixmap *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, TQFile::encodeName(itsName).data(),
|
|
FC_INDEX, FcTypeInteger, itsIndex,
|
|
FC_PIXEL_SIZE, FcTypeDouble, (double)size,
|
|
NULL);
|
|
return XftFontOpenPattern(KFI_DISPLAY(pix), pattern);
|
|
}
|
|
}
|
|
|
|
void CFcEngine::getSizes(TQPixmap *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 &&
|
|
TQString::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
|
|
|
|
}
|