//////////////////////////////////////////////////////////////////////////////// // // Namespae : KFI::Fontmap // Author : Craig Drummond // Project : K Font Installer // Creation Date : 06/06/2003 // 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, 2003, 2004 //////////////////////////////////////////////////////////////////////////////// #include "Fontmap.h" #include "FontEngine.h" #include "XConfig.h" #include "FcEngine.h" #include "KfiConstants.h" #include #include #include #include #include #include #include #include #include #include using namespace std; static const char * findSpace(const char *str) { while(str && *str!=' ' && *str!='\t') str++; return str; } static bool parseLine(const char *line, TQString &ps, TQString &fname, bool &isAlias) { static const int constMaxLen = 127; static const int constFileMaxLen = 1023; // // Format: // "/ () ; " // "/ /real ; " char a[constMaxLen+1], b[constFileMaxLen+1]; char *slash1=(char*)strchr(line, '/'), *space1=slash1 ? (char*)findSpace(slash1) : NULL, //strchr(slash1, ' ') : NULL, *ob=slash1 ? (char*)strchr(slash1, '(') : NULL, *cb=ob ? (char*)strchr(ob, ')') : NULL, *slash2=space1 && !ob && !cb ? (char*)strchr(space1, '/') : NULL, *space2=slash2 ? (char*)findSpace(slash2) : NULL, // strchr(slash2, ' ') : NULL, *semic=cb || space2 ? (char*)strchr(cb ? cb : space2, ';') : NULL; if(semic && space1-slash1 "TimesNewRoman" static TQString createX11PsName(const TQString &font) { TQString newName(font); unsigned int ch; bool newWord=true; newName.tqreplace(TQRegExp("\\-"), "_"); for(ch=0; chfileName() && ".."!=fInfo->fileName()) if(fInfo->isDir()) { if(!(str=locateFile(TQFile::encodeName(fInfo->filePath()+"/"), file, level+1)).isEmpty()) return str; } else if(fInfo->fileName()==file) return fInfo->filePath(); } } } return TQString(); } static TQString locateFile(const char *file, const char **dirs) { int d; TQString str; for(d=0; dirs[d]; ++d) if(!(str=locateFile(dirs[d], file)).isEmpty()) return str; return TQString::null; } #define FONTMAP "Fontmap" namespace KFI { namespace Fontmap { bool create(const TQString &dir, CFontEngine &fe) { bool root(Misc::root()), added=false; TQString fmapDir(Misc::dirSyntax(root ? KFI_ROOT_CFG_DIR : dir)); CFile old(fmapDir); TQStringList entries; int i; FcPattern *pat = FcPatternCreate(); FcObjectSet *os = FcObjectSetBuild(FC_FILE, FC_SCALABLE, (void*)0); FcFontSet *fs = FcFontList(0, pat, os); FcPatternDestroy(pat); FcObjectSetDestroy(os); for (i = 0; infont; i++) { TQString fName(Misc::fileSyntax(CFcEngine::getFcString(fs->fonts[i], FC_FILE))); FcBool scalable=FcFalse; if(!fName.isEmpty() && (root || dir.isEmpty() || 0==fName.tqfind(dir)) && FcResultMatch==FcPatternGetBool(fs->fonts[i], FC_SCALABLE, 0, &scalable) && scalable) { const TQStringList *existing=old.getEntries(fName); if(existing && existing->count()) entries+=(*existing); else { int face=0, numFaces=0; do { if(fe.openFont(fName, face)) { if(fe.hasPsInfo()) { if(0==numFaces) numFaces=fe.getNumFaces(); // Only really for TTC files... // // Add real addEntry(entries, fe.getPsName(), fName, fmapDir); added=true; // // Add fake entries for X11 generated names switch(fe.getWeight()) { case CFontEngine::WEIGHT_MEDIUM: case CFontEngine::WEIGHT_REGULAR: { TQString x11Ps(createX11PsName(fe.getFamilyName())); if(CFontEngine::ITALIC_ITALIC!=fe.getItalic() && CFontEngine::ITALIC_OBLIQUE!=fe.getItalic()) addAliasEntry(entries, createName(x11Ps, "Roman", getItalicStr(fe.getItalic())), fe.getPsName()); addAliasEntry(entries, createName(x11Ps, NULL, getItalicStr(fe.getItalic())), fe.getPsName()); break; } case CFontEngine::WEIGHT_UNKNOWN: break; default: addAliasEntry(entries, createName(createX11PsName(fe.getFamilyName()), CFontEngine::weightStr(fe.getWeight()), getItalicStr(fe.getItalic())), fe.getPsName()); } } fe.closeFont(); } } while(++facegsLine) { in.clear(); in.seekg(0, ios::end); int size= (streamoff) in.tellg(); in.seekg(0, ios::beg); char *buffer=new char[size+strlen(fmap)+strlen(constRLF)+5]; if(buffer) { bool added=false; buffer[0]='\0'; lineNum=0; do { in.getline(line, constMaxLineLen); if(in.good()) { line[constMaxLineLen-1]='\0'; if(lineNum>=ncLine && !added) { strcat(buffer, "("); strcat(buffer, fmap); strcat(buffer, ") "); strcat(buffer, constRLF); strcat(buffer, "\n"); added=true; } if(lineNum!=kfiLine) { strcat(buffer, line); strcat(buffer, "\n"); } lineNum++; } } while(!in.eof()); in.close(); if(added) // Don't re-write GS's Fontmap unless we've actually added something... { KSaveFile out(gsFile); TQTextStream *stream=out.textStream(); if(stream) *stream << buffer; } delete [] buffer; } } } } } return status; } CFile::CFile(const TQString &dir) : itsDir(dir), itsLineCount(0) { ifstream f(TQFile::encodeName(dir+FONTMAP)); itsEntries.setAutoDelete(true); if(f) { static const int constMaxLine=512; char line[constMaxLine+1]; TEntry *current=NULL; while(!f.eof()) { f.getline(line, constMaxLine); if(!f.eof()) { TQString ps, fname; bool isAlias; if(parseLine(line, ps, fname, isAlias)) { itsLineCount++; TEntry *entry=getEntry(¤t, fname, isAlias); if(!isAlias && entry && entry->psName.isEmpty()) entry->psName=ps; if(entry) entry->entries.append(line); } } } f.close(); } } const TQStringList * CFile::getEntries(const TQString &fname) { TEntry *entry=findEntry(0==fname.tqfind(itsDir) ? fname.mid(itsDir.length()) : fname, false); return entry ? &entry->entries : NULL; } CFile::TEntry * CFile::findEntry(const TQString &fname, bool isAlias) { TEntry *entry=NULL; for(entry=itsEntries.first(); entry; entry=itsEntries.next()) if(isAlias ? entry->psName==fname : entry->filename==fname) break; return entry; } CFile::TEntry * CFile::getEntry(TEntry **current, const TQString &fname, bool isAlias) { // // See if its the current one... if(*current && (isAlias ? (*current)->psName==fname : (*current)->filename==fname)) return *current; // // See if its already known... TEntry *entry=findEntry(fname, isAlias); // // If not found, then create a new entry if(!entry) { entry=new TEntry(fname); itsEntries.append(entry); } *current=entry; return entry; } } }