/* * KFontInst - KDE Font Installer * * Copyright 2003-2007 Craig Drummond * * ---- * * 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; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "FcEngine.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fixx11h.h" #include "File.h" //#define KFI_FC_DEBUG #define KFI_PREVIEW_GROUP "KFontInst Preview Settings" #define KFI_PREVIEW_STRING_KEY "String" namespace KFI { bool CFcEngine::theirFcDirty(true); const int CFcEngine::constScalableSizes[]={8, 10, 12, 24, 36, 48, 64, 72, 96, 0 }; const int CFcEngine::constDefaultAlphaSize=24; static int fcToQtWeight(int weight) { switch(weight) { case FC_WEIGHT_THIN: return 0; case FC_WEIGHT_EXTRALIGHT: return QFont::Light>>1; case FC_WEIGHT_LIGHT: return QFont::Light; default: case FC_WEIGHT_REGULAR: 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_DEMIBOLD: return QFont::DemiBold; case FC_WEIGHT_BOLD: return QFont::Bold; case FC_WEIGHT_EXTRABOLD: return (QFont::Bold+QFont::Black)>>1; case FC_WEIGHT_BLACK: return QFont::Black; } } #ifndef KFI_FC_NO_WIDTHS static int fcToQtWidth(int weight) { switch(weight) { case KFI_FC_WIDTH_ULTRACONDENSED: return QFont::UltraCondensed; case KFI_FC_WIDTH_EXTRACONDENSED: return QFont::ExtraCondensed; case KFI_FC_WIDTH_CONDENSED: return QFont::Condensed; case KFI_FC_WIDTH_SEMICONDENSED: return QFont::SemiCondensed; default: case KFI_FC_WIDTH_NORMAL: return QFont::Unstretched; case KFI_FC_WIDTH_SEMIEXPANDED: return QFont::SemiExpanded; case KFI_FC_WIDTH_EXPANDED: return QFont::Expanded; case KFI_FC_WIDTH_EXTRAEXPANDED: return QFont::ExtraExpanded; case KFI_FC_WIDTH_ULTRAEXPANDED: return QFont::UltraExpanded; } } #endif static bool fcToQtSlant(int slant) { return FC_SLANT_ROMAN==slant ? false : true; } inline bool equal(double d1, double d2) { return (fabs(d1 - d2) < 0.0001); } inline bool equalWeight(int a, int b) { return a==b || FC::weight(a)==FC::weight(b); } #ifndef KFI_FC_NO_WIDTHS inline bool equalWidth(int a, int b) { return a==b || FC::width(a)==FC::width(b); } #endif inline bool equalSlant(int a, int b) { return a==b || FC::slant(a)==FC::slant(b); } static void closeFont(XftFont *&font) { if(font) XftFontClose(QX11Info::display(), font); font=0L; } class CFcEngine::Xft { public: struct Pix { Pix() : currentW(0), currentH(0), allocatedW(0), allocatedH(0) { } static int getSize(int s) { static const int constBlockSize=64; return ((s/constBlockSize)+(s%constBlockSize ? 1 : 0))*constBlockSize; } bool allocate(int w, int h) { int requiredW=getSize(w), requiredH=getSize(h); currentW=w; currentH=h; if(requiredW!=allocatedW || requiredH!=allocatedH) { free(); if(w && h) { allocatedW=requiredW; allocatedH=requiredH; x11=XCreatePixmap(QX11Info::display(), RootWindow(QX11Info::display(), 0), allocatedW, allocatedH, DefaultDepth(QX11Info::display(), 0)); return true; } } return false; } void free() { if(allocatedW && allocatedH) { XFreePixmap(QX11Info::display(), x11); allocatedW=allocatedH=0; } } int currentW, currentH, allocatedW, allocatedH; Pixmap x11; }; Xft(); ~Xft(); bool init(const QColor &txt, const QColor &bgnd, int w, int h); void freeColors(); bool drawChar32Centre(XftFont *xftFont, quint32 ch, int w, int h) const; bool drawChar32(XftFont *xftFont, quint32 ch,int &x, int &y, int w, int h, int fontHeight, QRect &r) const; bool drawString(XftFont *xftFont, const QString &text, int x, int &y, int h) const; void drawString(const QString &text, int x, int &y, int h) const; bool drawGlyph(XftFont *xftFont, FT_UInt i, int &x, int &y, int w, int h, int fontHeight,bool oneLine, QRect &r) const; bool drawAllGlyphs(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine=false, int max=-1, QRect *used=0L) const; bool drawAllChars(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine=false, int max=-1, QRect *used=0L) const; QImage toImage(int w, int h) const; private: XftDraw *itsDraw; XftColor itsTxtColor, itsBgndColor; Pix itsPix; }; CFcEngine::Xft::Xft() { itsDraw=0L; itsTxtColor.color.alpha=0x0000; init(Qt::black, Qt::white, 64, 64); } CFcEngine::Xft::~Xft() { freeColors(); if(itsDraw) { XftDrawDestroy(itsDraw); itsDraw=0L; } } bool CFcEngine::Xft::init(const QColor &txt, const QColor &bnd, int w, int h) { if(itsDraw && (txt.red()<<8 != itsTxtColor.color.red || txt.green()<<8 != itsTxtColor.color.green || txt.blue()<<8 != itsTxtColor.color.blue || bnd.red()<<8 != itsBgndColor.color.red || bnd.green()<<8 != itsBgndColor.color.green || bnd.blue()<<8 != itsBgndColor.color.blue)) freeColors(); if(0x0000==itsTxtColor.color.alpha) { XRenderColor xrenderCol; Visual *visual=DefaultVisual(QX11Info::display(), 0); Colormap colorMap=DefaultColormap(QX11Info::display(), 0); xrenderCol.red=bnd.red()<<8; xrenderCol.green=bnd.green()<<8; xrenderCol.blue=bnd.green()<<8; xrenderCol.alpha=0xFFFF; XftColorAllocValue(QX11Info::display(), visual, colorMap, &xrenderCol, &itsBgndColor); xrenderCol.red=txt.red()<<8; xrenderCol.green=txt.green()<<8; xrenderCol.blue=txt.green()<<8; xrenderCol.alpha=0xFFFF; XftColorAllocValue(QX11Info::display(), visual, colorMap, &xrenderCol, &itsTxtColor); } if(itsPix.allocate(w, h) && itsDraw) XftDrawChange(itsDraw, itsPix.x11); if(!itsDraw) itsDraw=XftDrawCreate(QX11Info::display(), itsPix.x11, DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0)); if(itsDraw) XftDrawRect(itsDraw, &itsBgndColor, 0, 0, w, h); return itsDraw; } void CFcEngine::Xft::freeColors() { XftColorFree(QX11Info::display(), DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0), &itsTxtColor); XftColorFree(QX11Info::display(), DefaultVisual(QX11Info::display(), 0), DefaultColormap(QX11Info::display(), 0), &itsBgndColor); itsTxtColor.color.alpha=0x0000; } bool CFcEngine::Xft::drawChar32Centre(XftFont *xftFont, quint32 ch, int w, int h) const { if(XftCharExists(QX11Info::display(), xftFont, ch)) { XGlyphInfo extents; XftTextExtents32(QX11Info::display(), xftFont, &ch, 1, &extents); int rx(((w-extents.width)/2)+extents.x), ry(((h-extents.height)/2)+(extents.y)); XftDrawString32(itsDraw, &itsTxtColor, xftFont, rx, ry, &ch, 1); return true; } return false; } static const int constBorder=2; bool CFcEngine::Xft::drawChar32(XftFont *xftFont, quint32 ch, int &x, int &y, int w, int h, int fontHeight, QRect &r) const { r=QRect(); if(XftCharExists(QX11Info::display(), xftFont, ch)) { XGlyphInfo extents; XftTextExtents32(QX11Info::display(), xftFont, &ch, 1, &extents); if(extents.x>0) x+=extents.x; if(x+extents.width+constBorder>w) { x=0; if(extents.x>0) x+=extents.x; y+=fontHeight+constBorder; } if(y0) { y+=extents.height; return true; } return false; } void CFcEngine::Xft::drawString(const QString &text, int x, int &y, int h) const { QFont qt(KGlobalSettings::generalFont()); XftFont *xftFont=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(qt.family().toUtf8().data()), FC_WEIGHT, FcTypeInteger, qt.bold() ? FC_WEIGHT_BOLD : FC_WEIGHT_REGULAR, FC_SLANT, FcTypeInteger, qt.italic() ? FC_SLANT_ITALIC : FC_SLANT_ROMAN, FC_SIZE, FcTypeDouble, (double)qt.pointSize(), NULL); if(xftFont) { drawString(xftFont, text, x, y, h); closeFont(xftFont); } } bool CFcEngine::Xft::drawGlyph(XftFont *xftFont, FT_UInt i, int &x, int &y, int w, int h, int fontHeight, bool oneLine, QRect &r) const { XGlyphInfo extents; XftGlyphExtents(QX11Info::display(), xftFont, &i, 1, &extents); if(0==extents.width || 0==extents.height) { r=QRect(0, 0, 0, 0); return true; } if(x+extents.width+2>w) { if(oneLine) return false; x=0; y+=fontHeight+2; } if(ynum_glyphs && y0) { if(used) { if(used->isEmpty()) *used=r; else *used=used->united(r); } if(max>0 && ++drawn>=max) break; } } else break; if(oneLine) x=0; XftUnlockFace(xftFont); } } return rv; } bool CFcEngine::Xft::drawAllChars(XftFont *xftFont, int fontHeight, int &x, int &y, int w, int h, bool oneLine, int max, QRect *used) const { bool rv(false); if(xftFont) { FT_Face face=XftLockFace(xftFont); if(face) { int space(fontHeight/10), drawn(0); QRect r; if(!space) space=1; rv=true; y+=fontHeight; FT_Select_Charmap(face, FT_ENCODING_UNICODE); for(int cmap=0; cmapnum_charmaps; ++cmap) if(face->charmaps[cmap] && FT_ENCODING_ADOBE_CUSTOM==face->charmaps[cmap]->encoding) { FT_Select_Charmap(face, FT_ENCODING_ADOBE_CUSTOM); break; } for(unsigned int i=1; i<65535 && y0) { if(used) { if(used->isEmpty()) *used=r; else *used=used->united(r); } if(max>0 && ++drawn>=max) break; } } else break; } } if(oneLine) x=0; XftUnlockFace(xftFont); } } return rv; } QImage CFcEngine::Xft::toImage(int w, int h) const { return XftDrawPicture(itsDraw) ? QPixmap::fromX11Pixmap(itsPix.x11).toImage().copy(0, 0, w, h) : QImage(); } inline int point2Pixel(int point) { return (point*QX11Info::appDpiX()+36)/72; } static bool hasStr(XftFont *font, QString &str) { unsigned int slen=str.length(), ch; for(ch=0; chcharset, str[ch].unicode())) return false; return true; } static QString usableStr(XftFont *font, QString &str) { unsigned int slen=str.length(), ch; QString newStr; for(ch=0; chcharset, str[ch].unicode())) newStr+=str[ch]; return newStr; } static bool isFileName(const QString &name, quint32 style) { return QChar('/')==name[0] || KFI_NO_STYLE_INFO==style; } static void setTransparentBackground(QImage &img, const QColor &col) { // Convert background to transparent, and text to correct colour... img=img.convertToFormat(QImage::Format_ARGB32); for(int x=0; xh) { origHeight=h; h=bSize+8; } } if(xft()->init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, constInitialWidth, h)) { XftFont *xftFont=getFont(fSize); QString text(itsPreviewString); if(xftFont) { bool rv=false; int usedWidth=0; if(hasStr(xftFont, text) || hasStr(xftFont, text=text.toUpper()) || hasStr(xftFont, text=text.toLower())) { XGlyphInfo extents; const FcChar16 *str=(FcChar16 *)(text.utf16()); XftTextExtents16(QX11Info::display(), xftFont, str, text.length(), &extents); int y=(h-extents.height)/2; rv=xft()->drawString(xftFont, text, constOffset, y, h); usedWidth=extents.width; } else { int x=constOffset, y=constOffset; QRect used; rv=xft()->drawAllGlyphs(xftFont, fSize, x, y, constInitialWidth, h, true, text.length(), &used); if(rv) usedWidth=used.width(); } if(rv) { img=xft()->toImage(constInitialWidth, h); if(!img.isNull()) { if(origHeight) { int width=(int)((usedWidth*(double)(((double)h)/((double)origHeight)))+0.5); img=img.scaledToHeight(origHeight, Qt::SmoothTransformation) .copy(0, 0, width+(2*constOffset) &range, QList *chars) { QImage img; bool rv=false; if(chars) chars->clear(); if(!name.isEmpty() && ((name==itsName && style==itsStyle && File::equalIndex(faceNo, itsIndex)) || parse(name, style, faceNo)) ) { // // We allow kio_thumbnail to cache our thumbs. Normal is 128x128, and large is 256x256 // ...if kio_thumbnail asks us for a bigger size, then it is probably the file info dialog, in // which case treat it as a normal preview... if(thumb && (h>256 || w!=h)) thumb=false; int x=0, y=0; getSizes(); if(itsSizes.size()) { int imgWidth(thumb && itsScalable ? w*4 : w), imgHeight(thumb && itsScalable ? h*4 : h); bool needAlpha(bgnd.alpha()<255); if(xft()->init(needAlpha ? Qt::black : txt, needAlpha ? Qt::white : bgnd, imgWidth, imgHeight)) { XftFont *xftFont=NULL; int line1Pos(0), line2Pos(0); QRect used(0, 0, 0, 0); if(thumb) { QString text(itsScalable ? i18nc("First letter of the alphabet (in upper then lower case)", "Aa") : i18nc("All letters of the alphabet (in upper/lower case pairs), followed by numbers", "AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789")); // // Calculate size of text... int fSize=h; if(!itsScalable) // Then need to get nearest size... { int bSize=0; for(int s=0; s=(text.length()/2)) break; } if(itsScalable ? valid.length()!=text.length() : valid.length()<(text.length()/2)) xft()->drawAllChars(xftFont, fSize, x, y, imgWidth, imgHeight, true, itsScalable ? 2 : -1, itsScalable ? &used : NULL); else { QVector ucs4(valid.toUcs4()); QRect r; for(int ch=0; chdrawChar32(xftFont, ucs4[ch], x, y, imgWidth, imgHeight, fSize, r)) { if(used.isEmpty()) used=r; else used=used.united(r); } else break; } closeFont(xftFont); } } else if(0==range.count()) { QString lowercase(getLowercaseLetters()), uppercase(getUppercaseLetters()), punctuation(getPunctuation()); drawName(x, y, h); y+=4; line1Pos=y; y+=8; xftFont=getFont(alphaSize()); if(xftFont) { bool lc(hasStr(xftFont, lowercase)), uc(hasStr(xftFont, uppercase)), drawGlyphs=!lc && !uc; if(drawGlyphs) y-=8; else { QString validPunc(usableStr(xftFont, punctuation)); bool punc(validPunc.length()>=(punctuation.length()/2)); if(lc) xft()->drawString(xftFont, lowercase, x, y, h); if(uc) xft()->drawString(xftFont, uppercase, x, y, h); if(punc) xft()->drawString(xftFont, validPunc, x, y, h); if(lc || uc || punc) line2Pos=y+2; y+=8; } QString previewString(getPreviewString()); if(!drawGlyphs) { if(!lc && uc) previewString=previewString.toUpper(); if(!uc && lc) previewString=previewString.toLower(); } closeFont(xftFont); for(int s=0; sascent+xftFont->descent; rv=true; if(drawGlyphs) xft()->drawAllChars(xftFont, fontHeight, x, y, w, h, itsSizes.count()>1); else xft()->drawString(xftFont, previewString, x, y, h); closeFont(xftFont); } } } else if(1==range.count() && (range.first().null() || 0==range.first().to)) { if(range.first().null()) { drawName(x, y, h); if((xftFont=getFont(alphaSize()))) { int fontHeight=xftFont->ascent+xftFont->descent; xft()->drawAllGlyphs(xftFont, fontHeight, x, y, w, h, false); rv=true; closeFont(xftFont); } } else if((xftFont=getFont(int(imgWidth*0.85)))) { rv=xft()->drawChar32Centre(xftFont, (*(range.begin())).from, imgWidth, imgHeight); closeFont(xftFont); } } else { QList::ConstIterator it(range.begin()), end(range.end()); if((xftFont=getFont(alphaSize()))) { rv=true; drawName(x, y, h); y+=alphaSize(); bool stop=false; int fontHeight=xftFont->ascent+xftFont->descent, xOrig(x), yOrig(y); QRect r; for(it=range.begin(); it!=end && !stop; ++it) for(quint32 c=(*it).from; c<=(*it).to && !stop; ++c) { if(xft()->drawChar32(xftFont, c, x, y, w, h, fontHeight, r)) { if(chars && !r.isEmpty()) chars->append(TChar(r, c)); } else stop=true; } if(x==xOrig && y==yOrig) { // No characters found within the selected range... xft()->drawString(i18n("No characters found."), x, y, h); rv=true; } closeFont(xftFont); } } if(rv) { img=xft()->toImage(imgWidth, imgHeight); if(!img.isNull() && line1Pos) { QPainter p(&img); p.setPen(txt); p.drawLine(0, line1Pos, w-1, line1Pos); if(line2Pos) p.drawLine(0, line2Pos, w-1, line2Pos); } if(!img.isNull()) { if(itsScalable && !used.isEmpty() && (used.width(){}[]"); //krazy:exclude=i18ncheckarg } #ifdef KFI_USE_TRANSLATED_FAMILY_NAME // // Try to get the 'string' that matches the users KDE locale.. QString CFcEngine::getFcLangString(FcPattern *pat, const char *val, const char *valLang) { QString rv; QStringList kdeLangs=KGlobal::locale()->languageList(), fontLangs; QStringList::ConstIterator it(kdeLangs.begin()), end(kdeLangs.end()); // Create list of langs that this font's 'val' is encoded in... for(int i=0; true; ++i) { QString lang=getFcString(pat, valLang, i); if(lang.isEmpty()) break; else fontLangs.append(lang); } // Now go through the user's KDE locale, and try to find a font match... for(; it!=end; ++it) { int index=fontLangs.findIndex(*it); if(-1!=index) { rv=getFcString(pat, val, index); if(!rv.isEmpty()) break; } } if(rv.isEmpty()) rv=getFcString(pat, val, 0); return rv; } #endif QFont CFcEngine::getQFont(const QString &family, quint32 style, int size) { int weight, width, slant; FC::decomposeStyleVal(style, weight, width, slant); QFont font(family, size, fcToQtWeight(weight), fcToQtSlant(slant)); #ifndef KFI_FC_NO_WIDTHS font.setStretch(fcToQtWidth(width)); #endif return font; } bool CFcEngine::parse(const QString &name, quint32 style, int face) { if(name.isEmpty()) return false; reinit(); itsName=name; itsStyle=style; itsSizes.clear(); itsInstalled=!isFileName(name, style); if(!itsInstalled) { int count; FcPattern *pat=FcFreeTypeQuery((const FcChar8 *)(QFile::encodeName(itsName).data()), face<1 ? 0 : face, NULL, &count); if(!pat) return false; itsDescriptiveName=FC::createName(pat); FcPatternDestroy(pat); } else itsDescriptiveName=FC::createName(itsName, itsStyle); itsIndex=face<1 ? 0 : face; if(!itsInstalled) // Then add to fontconfig's list, so that Xft can display it... addFontFile(itsName); return true; } XftFont * CFcEngine::queryFont() { static const int constQuerySize=8; #ifdef KFI_FC_DEBUG kDebug(); #endif XftFont *f=getFont(constQuerySize); if(f && !isCorrect(f, true)) closeFont(f); if(itsInstalled && !f) { // Perhaps it is a newly installed font? If so try re-initialising fontconfig... theirFcDirty=true; reinit(); f=getFont(constQuerySize); // This time don't bother checking family - we've re-inited fc anyway, so things should be // up to date... And for "Symbol" Fc returns "Standard Symbols L", so wont match anyway! if(f && !isCorrect(f, false)) closeFont(f); } #ifdef KFI_FC_DEBUG kDebug() << "ret" << (int)f; #endif return f; } XftFont * CFcEngine::getFont(int size) { XftFont *f=NULL; #ifdef KFI_FC_DEBUG kDebug() << itsName << ' ' << itsStyle << ' ' << size; #endif if(itsInstalled) { int weight, width, slant; FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifndef KFI_FC_NO_WIDTHS if(KFI_NULL_SETTING!=width) f=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_WIDTH, FcTypeInteger, width, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); else #endif f=XftFontOpen(QX11Info::display(), 0, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); } else { FcPattern *pattern = FcPatternBuild(NULL, FC_FILE, FcTypeString, QFile::encodeName(itsName).constData(), FC_INDEX, FcTypeInteger, itsIndex<0 ? 0 : itsIndex, FC_PIXEL_SIZE, FcTypeDouble, (double)size, NULL); f=XftFontOpenPattern(QX11Info::display(), pattern); } #ifdef KFI_FC_DEBUG kDebug() << "ret: " << (int)f; #endif return f; } bool CFcEngine::isCorrect(XftFont *f, bool checkFamily) { int iv, weight, width, slant; FcChar8 *str; if(itsInstalled) FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifdef KFI_FC_DEBUG QString xxx; QTextStream s(&xxx); if(f) { if(itsInstalled) { s << "weight:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv)) s << iv << '/' << weight; else s << "no"; s << " slant:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv)) s << iv << '/' << slant; else s << "no"; s << " width:"; if(FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv)) s << iv << '/' << width; else s << "no"; s << " fam:"; if(checkFamily) if(FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str) s << QString::fromUtf8((char *)str) << '/' << itsName; else s << "no"; else s << "ok"; } else s << "NOT Installed... "; } else s << "No font!!! "; kDebug() << "isCorrect? " << xxx; #endif return f ? itsInstalled ? FcResultMatch==FcPatternGetInteger(f->pattern, FC_WEIGHT, 0, &iv) && equalWeight(iv, weight) && FcResultMatch==FcPatternGetInteger(f->pattern, FC_SLANT, 0, &iv) && equalSlant(iv, slant) && #ifndef KFI_FC_NO_WIDTHS (KFI_NULL_SETTING==width || (FcResultMatch==FcPatternGetInteger(f->pattern, FC_WIDTH, 0, &iv) && equalWidth(iv, width))) && #endif (!checkFamily || (FcResultMatch==FcPatternGetString(f->pattern, FC_FAMILY, 0, &str) && str && QString::fromUtf8((char *)str)==itsName)) : (itsIndex<0 || (FcResultMatch==FcPatternGetInteger(f->pattern, FC_INDEX, 0, &iv) && itsIndex==iv)) && FcResultMatch==FcPatternGetString(f->pattern, FC_FILE, 0, &str) && str && QString::fromUtf8((char *)str)==itsName : false; } void CFcEngine::getSizes() { if(!itsSizes.isEmpty()) return; #ifdef KFI_FC_DEBUG kDebug(); #endif XftFont *f=queryFont(); int alphaSize(itsSizes.size()>itsAlphaSizeIndex && itsAlphaSizeIndex>=0 ? itsSizes[itsAlphaSizeIndex] : constDefaultAlphaSize); itsScalable=FcTrue; itsAlphaSizeIndex=0; if(f) { bool gotSizes=false; double px(0.0); if(itsInstalled) { if(FcResultMatch!=FcPatternGetBool(f->pattern, FC_SCALABLE, 0, &itsScalable)) itsScalable=FcFalse; if(!itsScalable) { FcPattern *pat=NULL; FcObjectSet *os = FcObjectSetBuild(FC_PIXEL_SIZE, (void*)0); int weight, width, slant; FC::decomposeStyleVal(itsStyle, weight, width, slant); #ifndef KFI_FC_NO_WIDTHS if(KFI_NULL_SETTING!=width) pat=FcPatternBuild(NULL, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, FC_WIDTH, FcTypeInteger, width, NULL); else #endif pat=FcPatternBuild(NULL, FC_FAMILY, FcTypeString, (const FcChar8 *)(itsName.toUtf8().data()), FC_WEIGHT, FcTypeInteger, weight, FC_SLANT, FcTypeInteger, slant, NULL); FcFontSet *set=FcFontList(0, pat, os); FcPatternDestroy(pat); FcObjectSetDestroy(os); if (set) { int size(0); #ifdef KFI_FC_DEBUG kDebug() << "got fixed sizes: " << set->nfont; #endif itsSizes.reserve(set->nfont); for (int i = 0; i < set->nfont; i++) if(FcResultMatch==FcPatternGetDouble(set->fonts[i], FC_PIXEL_SIZE, 0, &px)) { gotSizes=true; itsSizes.push_back((int)px); #ifdef KFI_FC_DEBUG kDebug() << "got fixed: " << px; #endif if (px<=alphaSize) itsAlphaSizeIndex=size; size++; } FcFontSetDestroy(set); } } } 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); #ifdef KFI_FC_DEBUG kDebug() << "numSizes fixed: " << numSizes; #endif for (size=0; size= 20105 double px=face->available_sizes[size].y_ppem>>6; #else double px=face->available_sizes[size].width; #endif #ifdef KFI_FC_DEBUG kDebug() << "px: " << px; #endif itsSizes.push_back((int)px); if (px<=alphaSize) itsAlphaSizeIndex=size; } } XftUnlockFace(f); } } closeFont(f); } if(itsScalable) { itsSizes.reserve(sizeof(constScalableSizes)/sizeof(int)); for (int i=0; constScalableSizes[i]; ++i) { int px=point2Pixel(constScalableSizes[i]); if (px<=alphaSize) itsAlphaSizeIndex=i; itsSizes.push_back(px); } } #ifdef KFI_FC_DEBUG kDebug() << "end"; #endif } void CFcEngine::drawName(int x, int &y, int h) { QString title(itsDescriptiveName.isEmpty() ? i18n("ERROR: Could not determine font's name.") : itsDescriptiveName); if(1==itsSizes.size()) title=i18np("%2 [1 pixel]", "%2 [%1 pixels]", itsSizes[0], title); xft()->drawString(title, x, y, h); } void CFcEngine::addFontFile(const QString &file) { if(!itsAddedFiles.contains(file)) { FcInitReinitialize(); FcConfigAppFontAddFile(FcConfigGetCurrent(), (const FcChar8 *)(QFile::encodeName(file).data())); itsAddedFiles.append(file); } } void CFcEngine::reinit() { if(theirFcDirty) { FcInitReinitialize(); theirFcDirty=false; } } CFcEngine::Xft * CFcEngine::xft() { if(!itsXft) itsXft=new Xft; return itsXft; } }