Scribus Developer Documentation - API
logo-pen

Scribus Developer Documentation - API

scfonts.cpp

Go to the documentation of this file.
00001 /*
00002 For general Scribus (>=1.3.2) copyright and licensing information please refer
00003 to the COPYING file provided with the program. Following this notice may exist
00004 a copyright and/or license notice that predates the release of Scribus 1.3.2
00005 for which a new license (GPL+exception) is in place.
00006 */
00007 /*
00008     Scribus font handling code - copyright (C) 2001 by
00009     Alastair M. Robinson
00010 
00011     Based on code by Christian Tpp and Franz Schmid.
00012 
00013     Contributed to the Scribus project under the terms of
00014     the GNU General Public License version 2, or any later
00015     version, at your discretion.
00016 */
00017 
00018 #include <QApplication>
00019 #include <QDir>
00020 #include <QDomDocument>
00021 #include <QFile>
00022 #include <QFileInfo>
00023 #include <QFont>
00024 #include <QGlobalStatic>
00025 #include <QMap>
00026 #include <QRegExp>
00027 #include <QString>
00028 
00029 
00030 #include <cstdlib>
00031 #include "scfonts.h"
00032 #include "fonts/ftface.h"
00033 #include "fonts/scface_ps.h"
00034 #include "fonts/scface_ttf.h"
00035 #include "fonts/scfontmetrics.h"
00036 
00037 #include "prefsmanager.h"
00038 #include "prefsfile.h"
00039 #include "prefscontext.h"
00040 #include "prefstable.h"
00041 #include "scribus.h"
00042 #include "scribuscore.h"
00043 #ifdef Q_WS_X11
00044 #include <X11/X.h>
00045 #include <X11/Xlib.h>
00046 #endif
00047 
00048 #ifdef HAVE_FONTCONFIG
00049 #include <fontconfig/fontconfig.h>
00050 #endif
00051 
00052 #include FT_TRUETYPE_TAGS_H
00053 #include FT_TRUETYPE_TABLES_H
00054 
00055 
00056 #include "scpaths.h"
00057 #include "util.h"
00058 
00059 
00060 
00061 /***************************************************************************/
00062 
00063 SCFonts::SCFonts() : QMap<QString,ScFace>(), FontPath()
00064 {
00065 //  insert("", ScFace::none()); // Wtf why inserting an empty entry here ????
00066     showFontInformation=false;
00067     checkedFonts.clear();
00068 }
00069 
00070 SCFonts::~SCFonts()
00071 {
00072 }
00073 
00074 void SCFonts::updateFontMap()
00075 {
00076     fontMap.clear();
00077     SCFontsIterator it( *this );
00078     for ( ; it.hasNext(); it.next())
00079     {
00080         if (it.current().usable())
00081         {
00082             if (fontMap.contains(it.current().family()))
00083             {
00084                 if (!fontMap[it.current().family()].contains(it.current().style()))
00085                 {
00086                     fontMap[it.current().family()].append(it.current().style());
00087                 }
00088             }
00089             else
00090             {
00091                 QStringList styles;
00092                 styles.append(it.current().style());
00093                 fontMap.insert(it.current().family(), styles);
00094             }
00095         }
00096     }
00097 }
00098 
00099 /* Add a path to the list of fontpaths, ensuring that
00100    a trailing slash is present.
00101    Checks to make sure this path is not already present
00102    before adding.
00103 */
00104 void SCFonts::AddPath(QString p)
00105 {
00106     if(p.right(1) != "/")
00107       p += "/";
00108     if(!FontPath.contains(p))
00109         FontPath.insert(FontPath.count(),p);
00110 }
00111 
00112 void SCFonts::AddScalableFonts(const QString &path, QString DocName)
00113 {
00114     //Make sure this is not empty or we will scan the whole drive on *nix
00115     //QString::null+/ is / of course.
00116     if (path.isEmpty())
00117         return;
00118     FT_Library library = NULL;
00119     QString pathfile;
00120     bool error;
00121     error = FT_Init_FreeType( &library );
00122     QString pathname(path);
00123     if ( !pathname.endsWith("/") )
00124         pathname += "/";
00125     pathname=QDir::convertSeparators(pathname);
00126     QDir d(pathname, "*", QDir::Name, QDir::Dirs | QDir::Files | QDir::Readable);
00127     if ((d.exists()) && (d.count() != 0))
00128     {
00129         for (uint dc = 0; dc < d.count(); ++dc)
00130         {
00131             // readdir may return . or .., which we don't want to recurse
00132             // over. Skip 'em.
00133             if (d[dc] == "." || d[dc] == "..")
00134                 continue;
00135             QFileInfo fi(pathname+d[dc]);
00136             if (!fi.exists())      // Sanity check for broken Symlinks
00137                 continue;
00138             
00139             qApp->processEvents();
00140             
00141             if (fi.isSymLink())
00142             {
00143                 QFileInfo fi3(fi.readLink());
00144                 if (fi3.isRelative())
00145                     pathfile = pathname+fi.readLink();
00146                 else
00147                     pathfile = fi3.absoluteFilePath();
00148             }
00149             else
00150                 pathfile = pathname+d[dc];
00151             QFileInfo fi2(pathfile);
00152             if (fi2.isDir()) 
00153             {
00154                 if (DocName.isEmpty())
00155                     AddScalableFonts(pathfile);
00156                 continue;
00157             }
00158             QString ext = fi.suffix().toLower();
00159             QString ext2 = fi2.suffix().toLower();
00160             if ((ext != ext2) && (ext.isEmpty())) 
00161                 ext = ext2;
00162             if ((ext == "ttc") || (ext == "dfont") || (ext == "pfa") || (ext == "pfb") || (ext == "ttf") || (ext == "otf"))
00163             {
00164                 error = AddScalableFont(pathfile, library, DocName);
00165             }
00166 #ifdef Q_OS_MAC
00167             else if (ext.isEmpty() && DocName.isEmpty())
00168             {
00169                 error = AddScalableFont(pathfile, library, DocName);
00170                 if (error)
00171                     error = AddScalableFont(pathfile + "/..namedfork/rsrc",library, DocName);
00172             }
00173 #endif              
00174         }
00175     }
00176     FT_Done_FreeType( library );
00177 }
00178 
00179 
00180 /*****
00181    What to do with font files:
00182    - note mod. date
00183    - in FontCache?  => load faces from cache
00184    - load via FT    => or broken
00185    - for all faces:
00186        load face
00187        get fontinfo (type, names, styles, global metrics)
00188        check encoding(s)
00189        (calc. hash sum)
00190        create cache entry
00191  *****/
00192 
00193 
00197 void getFontFormat(FT_Face face, ScFace::FontFormat & fmt, ScFace::FontType & type)
00198 {
00199     static const char* T42_HEAD      = "%!PS-TrueTypeFont";
00200     static const char* T1_HEAD      = "%!FontType1";
00201     static const char* T1_ADOBE_HEAD = "%!PS-AdobeFont-1";
00202     static const char* PSFONT_ADOBE2_HEAD  = "%!PS-Adobe-2.0 Font";
00203     static const char* PSFONT_ADOBE21_HEAD  = "%!PS-Adobe-2.1 Font";
00204     static const char* PSFONT_ADOBE3_HEAD  = "%!PS-Adobe-3.0 Resource-Font";
00205     static const int   FONT_NO_ERROR = 0;
00206     
00207     const FT_Stream fts = face->stream;
00208     char buf[128];
00209     
00210     fmt = ScFace::UNKNOWN_FORMAT;
00211     type = ScFace::UNKNOWN_TYPE;
00212     if (ftIOFunc(fts, 0L, reinterpret_cast<FT_Byte *>(buf), 128) == FONT_NO_ERROR) 
00213     {
00214         if(strncmp(buf,T42_HEAD,strlen(T42_HEAD)) == 0) 
00215         {
00216             fmt = ScFace::TYPE42;
00217             type = ScFace::TTF;
00218         }
00219         else if(strncmp(buf,T1_HEAD,strlen(T1_HEAD)) == 0 ||
00220                 strncmp(buf,T1_ADOBE_HEAD,strlen(T1_ADOBE_HEAD)) == 0) 
00221         {
00222             fmt = ScFace::PFA;
00223             type = ScFace::TYPE1;
00224         }
00225         else if(strncmp(buf,PSFONT_ADOBE2_HEAD,strlen(PSFONT_ADOBE2_HEAD)) == 0 ||
00226                 strncmp(buf,PSFONT_ADOBE21_HEAD,strlen(PSFONT_ADOBE21_HEAD)) == 0 ||
00227                 strncmp(buf,PSFONT_ADOBE3_HEAD,strlen(PSFONT_ADOBE3_HEAD)) ==0) 
00228         {
00229             // Type2(CFF), Type0(Composite/CID), Type 3, Type 14 etc would end here
00230             fmt = ScFace::PFA;
00231             type = ScFace::UNKNOWN_TYPE;
00232         }
00233         else if(buf[0] == '\200' && buf[1] == '\1')
00234         {
00235             fmt = ScFace::PFB;
00236             type = ScFace::TYPE1;
00237         }
00238         else if(buf[0] == '\0' && buf[1] == '\1' 
00239                 && buf[2] == '\0' && buf[3] == '\0')
00240         {
00241             fmt = ScFace::SFNT;
00242             type = ScFace::TTF;
00243         }
00244         else if(strncmp(buf,"true",4) == 0)
00245         {
00246             fmt = ScFace::SFNT;
00247             type = ScFace::TTF;
00248         }
00249         else if(strncmp(buf,"ttcf",4) == 0)
00250         {
00251             fmt = ScFace::TTCF;
00252             type = ScFace::OTF;
00253         }
00254         else if(strncmp(buf,"OTTO",4) == 0)
00255         {
00256             fmt = ScFace::SFNT;
00257             type = ScFace::OTF;
00258         }
00259         // missing: raw CFF
00260     }
00261 }
00262 
00267 void getSFontType(FT_Face face, ScFace::FontType & type) 
00268 {
00269     if (FT_IS_SFNT(face)) 
00270     {
00271         FT_ULong ret = 0;
00272         bool hasGlyph = ! FT_Load_Sfnt_Table(face, TTAG_glyf, 0, NULL,  &ret);
00273         hasGlyph &= ret > 0;
00274         bool hasCFF = ! FT_Load_Sfnt_Table(face, TTAG_CFF, 0, NULL,  &ret);
00275         hasCFF &= ret > 0;
00276         if (hasGlyph)
00277             type = ScFace::TTF;
00278         else if (hasCFF)
00279             type = ScFace::OTF;
00280         // TODO: CID or no
00281     }
00282 } 
00283 
00284 // Load a single font into the library from the passed filename. Returns true on error.
00285 bool SCFonts::AddScalableFont(QString filename, FT_Library &library, QString DocName)
00286 {
00287     static bool firstRun;
00288     bool Subset = false;
00289     char *buf[50];
00290     QString glyName = "";
00291     ScFace::FontFormat format;
00292     ScFace::FontType   type;
00293     FT_Face         face = NULL;
00294     struct testCache foCache;
00295     QFileInfo fic(filename);
00296     foCache.isOK = false;
00297     foCache.isChecked = true;
00298     foCache.lastMod = fic.lastModified();
00299     if (checkedFonts.count() == 0)
00300     {
00301         firstRun = true;
00302         ScCore->setSplashStatus( QObject::tr("Creating Font Cache") );
00303     }
00304     bool error = FT_New_Face( library, QFile::encodeName(filename), 0, &face );
00305     if (error) 
00306     {
00307         if (face != NULL)
00308             FT_Done_Face( face );
00309         checkedFonts.insert(filename, foCache);
00310         if (showFontInformation)
00311             sDebug(QObject::tr("Font %1 is broken, discarding it").arg(filename));
00312         return true;
00313     }
00314     getFontFormat(face, format, type);
00315     if (format == ScFace::UNKNOWN_FORMAT) 
00316     {
00317         if (showFontInformation)
00318             sDebug(QObject::tr("Failed to load font %1 - font type unknown").arg(filename));
00319         checkedFonts.insert(filename, foCache);
00320         error = true;
00321     }
00322     bool HasNames = FT_HAS_GLYPH_NAMES(face);
00323     if (!error)
00324     {
00325         if (!checkedFonts.contains(filename))
00326         {
00327             if (!firstRun)
00328                 ScCore->setSplashStatus( QObject::tr("New Font found, checking...") );
00329             FT_UInt gindex = 0;
00330             FT_ULong charcode = FT_Get_First_Char( face, &gindex );
00331             while ( gindex != 0 )
00332             {
00333                 error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
00334                 if (error)
00335                 {
00336                     if (showFontInformation)
00337                         sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(filename).arg(gindex).arg(charcode));
00338                     if (face != NULL)
00339                         FT_Done_Face( face );
00340                     checkedFonts.insert(filename, foCache);
00341                     return true;
00342                 }
00343                 FT_Get_Glyph_Name(face, gindex, buf, 50);
00344                 QString newName = QString(reinterpret_cast<char*>(buf));
00345                 if (newName == glyName)
00346                 {
00347                     HasNames = false;
00348                     Subset = true;
00349                 }
00350                 glyName = newName;
00351                 charcode = FT_Get_Next_Char( face, charcode, &gindex );
00352             }
00353             foCache.isOK = true;
00354             checkedFonts.insert(filename, foCache);
00355         }
00356         else
00357         {
00358             if (!checkedFonts[filename].isOK)
00359             {
00360                 checkedFonts[filename].isChecked = true;
00361                 return true;
00362             }
00363             if (checkedFonts[filename].lastMod != fic.lastModified())
00364             {
00365                 ScCore->setSplashStatus( QObject::tr("Modified Font found, checking...") );
00366                 FT_UInt gindex = 0;
00367                 FT_ULong charcode = FT_Get_First_Char( face, &gindex );
00368                 while ( gindex != 0 )
00369                 {
00370                     error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
00371                     if (error)
00372                     {
00373                         if (showFontInformation)
00374                             sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(filename).arg(gindex).arg(charcode));
00375                         if (face != NULL)
00376                             FT_Done_Face( face );
00377                         checkedFonts.insert(filename, foCache);
00378                         return true;
00379                     }
00380                     FT_Get_Glyph_Name(face, gindex, buf, 50);
00381                     QString newName = QString(reinterpret_cast<char*>(buf));
00382                     if (newName == glyName)
00383                     {
00384                         HasNames = false;
00385                         Subset = true;
00386                     }
00387                     glyName = newName;
00388                     charcode = FT_Get_Next_Char( face, charcode, &gindex );
00389                 }
00390                 foCache.isOK = true;
00391                 checkedFonts[filename] = foCache;
00392             }
00393             else
00394             {
00395                 checkedFonts[filename].isOK = true;
00396                 checkedFonts[filename].isChecked = true;
00397             }
00398         }
00399     }
00400     int faceindex=0;
00401     while (!error)
00402     {
00403         QString fam(face->family_name);
00404         QString sty(face->style_name);
00405         if (sty == "Regular")
00406         {
00407             switch (face->style_flags)
00408             {
00409                 case 0:
00410                     break;
00411                 case 1:
00412                     sty = "Italic";
00413                     break;
00414                 case 2:
00415                     sty = "Bold";
00416                     break;
00417                 case 3:
00418                     sty = "Bold Italic";
00419                     break;
00420                 default:
00421                     break;
00422             }
00423         }
00424         QString ts(fam + " " + sty);
00425         QString alt("");
00426         const char* psName = FT_Get_Postscript_Name(face);
00427         QString qpsName;
00428         if (psName)
00429             qpsName = QString(psName);
00430         else
00431             qpsName = ts;
00432         ScFace t;
00433         if (contains(ts))
00434         {
00435             t = (*this)[ts];
00436             if (t.psName() != qpsName)
00437             {
00438                 alt = " ("+qpsName+")";
00439                 ts += alt;
00440                 sty += alt;
00441             }
00442         }
00443         t = (*this)[ts];
00444         if (t.isNone())
00445         {
00446             switch (format) 
00447             {
00448                 case ScFace::PFA:
00449                     t = ScFace(new ScFace_pfa(fam, sty, "", ts, qpsName, filename, faceindex));
00450                     t.subset(Subset);
00451                     break;
00452                 case ScFace::PFB:
00453                     t = ScFace(new ScFace_pfb(fam, sty, "", ts, qpsName, filename, faceindex));
00454                     t.subset(Subset);
00455                     break;
00456                 case ScFace::SFNT:
00457                     t = ScFace(new ScFace_ttf(fam, sty, "", ts, qpsName, filename, faceindex));
00458                     getSFontType(face, t.m->typeCode);
00459                     if (t.type() == ScFace::OTF) 
00460                     {
00461                         t.subset(true);
00462                     }
00463                     else
00464                         t.subset(Subset);
00465                     break;
00466                 case ScFace::TTCF:
00467                     t = ScFace(new ScFace_ttf(fam, sty, "", ts, qpsName, filename, faceindex));
00468                     t.m->formatCode = ScFace::TTCF;
00469                     t.m->typeCode = ScFace::TTF;
00470                     //getSFontType(face, t.m->typeCode);
00471                     if (t.type() == ScFace::OTF) 
00472                     {
00473                         t.subset(true);
00474                     }
00475                     else
00476                         t.subset(Subset);
00477                     break;
00478                 case ScFace::TYPE42:
00479                     t = ScFace(new ScFace_ttf(fam, sty, "", ts, qpsName, filename, faceindex));
00480                     getSFontType(face, t.m->typeCode);
00481                     if (t.type() == ScFace::OTF) 
00482                     {
00483                         t.subset(true);
00484                     }
00485                     else
00486                         t.subset(Subset);
00487                     break;
00488                 default:
00489                 /* catching any types not handled above to silence compiler */
00490                     break;
00491             }
00492             insert(ts,t);
00493             t.m->hasNames = HasNames;
00494             t.embedPs(true);
00495             t.usable(true);
00496             t.m->status = ScFace::UNKNOWN;
00497             if (face->num_glyphs > 2048)
00498                 t.subset(true);
00499             t.m->forDocument = DocName;
00500             //setBestEncoding(face); //AV
00501 /*          switch (face->charmap? face->charmap->encoding : -1)
00502             {
00503                 case     FT_ENCODING_ADOBE_STANDARD: 
00504                     t->FontEnc = QString("StandardEncoding");
00505                     break;
00506                 case     FT_ENCODING_APPLE_ROMAN: 
00507                     t->FontEnc = QString("MacRomanEncoding");
00508                     break;
00509                 case     FT_ENCODING_ADOBE_EXPERT: 
00510                     t->FontEnc = QString("MacExpertEncoding");
00511                     break;
00512                 case     FT_ENCODING_ADOBE_LATIN_1: 
00513                     t->FontEnc = QString("WinAnsiEncoding");
00514                     break;
00515                 case     FT_ENCODING_UNICODE: 
00516                     t->FontEnc = QString("Unicode");
00517                     break;
00518                 default:
00519                     t->FontEnc = QString();
00520             }
00521 */          if (showFontInformation)
00522                 sDebug(QObject::tr("Font %1 loaded from %2(%3)").arg(t.psName()).arg(filename).arg(faceindex+1));
00523 
00524 /*
00525 //debug
00526             QByteArray bb;
00527             t->RawData(bb);
00528             QFile dump(QString("/tmp/fonts/%1-%2").arg(ts).arg(psName));
00529             dump.open(IO_WriteOnly);
00530             QDataStream os(&dump);
00531             os.writeRawBytes(bb.data(), bb.size());
00532             dump.close();
00533 */
00534         }
00535         else 
00536         {
00537             if (showFontInformation)
00538                 sDebug(QObject::tr("Font %1(%2) is duplicate of %3").arg(filename).arg(faceindex+1).arg(t.fontPath()));
00539             // this is needed since eg. AppleSymbols will happily return a face for *any* face_index
00540             if (faceindex > 0) {
00541                 break;
00542             }
00543         }
00544         FT_Done_Face(face);
00545         face=NULL;
00546         ++faceindex;
00547         error = FT_New_Face( library, QFile::encodeName(filename), faceindex, &face );
00548     } //while
00549     
00550     if (face != 0)
00551         FT_Done_Face( face );
00552     return error && faceindex == 0;
00553 }
00554 
00555 void SCFonts::removeFont(QString name)
00556 {
00557     remove(name);
00558     updateFontMap();
00559 }
00560 
00561 const ScFace& SCFonts::findFont(const QString& fontname, ScribusDoc *doc)
00562 {
00563     if (fontname.isEmpty())
00564         return ScFace::none();
00565     
00566     PrefsManager* prefsManager = PrefsManager::instance();
00567     
00568     if (!contains(fontname) || !(*this)[fontname].usable())
00569     {
00570         QString replFont;
00571         if ((!prefsManager->appPrefs.GFontSub.contains(fontname)) || (!(*this)[prefsManager->appPrefs.GFontSub[fontname]].usable()))
00572         {
00573             replFont = doc ? doc->toolSettings.defFont : prefsManager->appPrefs.toolSettings.defFont;
00574         }
00575         else
00576             replFont = prefsManager->appPrefs.GFontSub[fontname];
00577         ScFace repl = (*this)[replFont].mkReplacementFor(fontname, doc ? doc->DocName : QString(""));
00578         insert(fontname, repl);
00579     }
00580     else if ( doc && !doc->UsedFonts.contains(fontname) )
00581     {
00582         doc->AddFont(fontname, qRound(doc->toolSettings.defSize / 10.0));
00583     }
00584     return (*this)[fontname];   
00585 }
00586 
00587 
00588 QMap<QString,QString> SCFonts::getSubstitutions(const QList<QString> skip) const
00589 {
00590     QMap<QString,QString> result;
00591     QMap<QString,ScFace>::ConstIterator it;
00592     for (it = begin(); it != end(); ++it)
00593     {
00594         if (it.value().isReplacement() && !skip.contains(it.key()))
00595             result[it.key()] = it.value().replacementName();
00596     }
00597     return result;
00598 }
00599 
00600 
00601 void SCFonts::setSubstitutions(const QMap<QString,QString>& substitutes, ScribusDoc* doc)
00602 {
00603     QMap<QString,QString>::ConstIterator it;
00604     for (it = substitutes.begin(); it != substitutes.end(); ++it)
00605     {
00606         if (it.key() == it.value())
00607             continue;
00608         ScFace& font(const_cast<ScFace&>(findFont(it.key(), doc)));
00609         if (font.isReplacement())
00610         {
00611             font.chReplacementTo(const_cast<ScFace&>(findFont(it.value(), doc)), doc->DocName);
00612         }
00613     }
00614 }
00615 
00616 
00617 #ifdef HAVE_FONTCONFIG
00618 // Use Fontconfig to locate and load fonts.
00619 void SCFonts::AddFontconfigFonts()
00620 {
00621     // All-in-one library setup. Perhaps this should be in
00622     // the SCFonts constructor.
00623     FcConfig* FcInitLoadConfigAndFonts();
00624     // The pattern controls what fonts to match. In this case we want to
00625     // match all scalable fonts, but ignore bitmap fonts.
00626     FcPattern* pat = FcPatternBuild(NULL,
00627                                     FC_SCALABLE, FcTypeBool, true,
00628                                     NULL);
00629     // The ObjectSet tells FontConfig what information about each match to return.
00630     // We currently just need FC_FILE, but other info like font family and style
00631     // is available - see "man fontconfig".
00632     FcObjectSet* os = FcObjectSetBuild (FC_FILE, (char *) 0);
00633     // Now ask fontconfig to retrieve info as specified in 'os' about fonts
00634     // matching pattern 'pat'.
00635     FcFontSet* fs = FcFontList(0, pat, os);
00636     FcObjectSetDestroy(os);
00637     FcPatternDestroy(pat);
00638     // Create the Freetype library
00639     bool error;
00640     FT_Library library = NULL;
00641     error = FT_Init_FreeType( &library );
00642     // Now iterate over the font files and load them
00643     int i;
00644     for (i = 0; i < fs->nfont; i++) 
00645     {
00646         FcChar8 *file = NULL;
00647         if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch)
00648         {
00649             if (showFontInformation)
00650                 sDebug(QObject::tr("Loading font %1 (found using fontconfig)").arg(QString((char*)file)));
00651             error = AddScalableFont(QString((char*)file), library, "");
00652         }
00653         else
00654             if (showFontInformation)
00655                 sDebug(QObject::tr("Failed to load a font - freetype2 couldn't find the font file"));
00656     }
00657     FT_Done_FreeType( library );
00658 }
00659 
00660 #elif defined(Q_WS_X11)
00661 
00662 void SCFonts::AddXFontPath()
00663 {
00664     int pathcount,i;
00665     Display *display=XOpenDisplay(NULL);
00666     char **fontpath=XGetFontPath(display,&pathcount);
00667     for(i=0; i<pathcount; ++i)
00668         AddPath(fontpath[i]);
00669     XFreeFontPath(fontpath);
00670 }
00671 
00672 /* replacement for AddXFontServerPath() for correctly parsing
00673  * RedHad-Style /etc/X11/fs/config files */
00674 
00675 void SCFonts::AddXFontServerPath()
00676 {
00677     QFile fs("/etc/X11/fs/config");
00678     if(!(fs.exists()))
00679     {
00680         fs.setName("/usr/X11R6/lib/X11/fs/config");
00681         if(!(fs.exists()))
00682         {
00683             fs.setName("/usr/X11/lib/X11/fs/config");
00684             if(!(fs.exists()))
00685                 return;
00686         }
00687     }
00688 
00689     if (fs.open(QIODevice::ReadOnly))
00690     {
00691         QString fsconfig,paths,tmp;
00692         QTextStream tsx(&fs);
00693         fsconfig = tsx.readAll();
00694         fs.close();
00695 
00696         int pos = fsconfig.find("catalogue");
00697         paths = fsconfig.mid(pos);
00698         paths = paths.mid(paths.find("=")+1);
00699 
00700         pos=0;
00701         do {
00702             pos = paths.find("\n",pos+1);
00703         } while (pos > -1 && paths.mid(pos-1, 1) == ",");
00704 
00705         if(pos<0) pos=paths.length();
00706         paths = paths.left(pos);
00707         paths = paths.simplified();
00708         paths.replace(QRegExp(" "), "");
00709         paths.replace(QRegExp(","), "\n");
00710         paths += "\n";
00711         paths = paths.trimmed();
00712 
00713         pos=-1;
00714         do {
00715             int pos2;
00716             pos2 = paths.find("\n",pos+1);
00717             tmp = paths.mid(pos+1,(pos2-pos)-1);
00718             pos=pos2;
00719 
00720             AddPath(tmp);
00721 
00722         } while (pos > -1);
00723     }
00724 }
00725 #endif
00726 
00727 /* Add an extra path to our font search path,
00728  * allowing a user to have extra fonts installed
00729  * only for this user. Can also be used also as an emergency
00730  * fallback if no suitable fonts are found elsewere */
00731 void SCFonts::AddUserPath(QString )
00732 {
00733     PrefsContext *pc = PrefsManager::instance()->prefsFile->getContext("Fonts");
00734     PrefsTable *extraDirs = pc->getTable("ExtraFontDirs");
00735     for (int i = 0; i < extraDirs->getRowCount(); ++i)
00736         AddPath(extraDirs->get(i, 0));
00737 }
00738 
00739 void SCFonts::ReadCacheList(QString pf)
00740 {
00741     QFile fr(pf + "/cfonts.xml");
00742     QFileInfo fir(fr);
00743     if (fir.exists())
00744         fr.remove();
00745     checkedFonts.clear();
00746     struct testCache foCache;
00747     QDomDocument docu("fontcacherc");
00748     QFile f(pf + "/checkfonts.xml");
00749     if(!f.open(QIODevice::ReadOnly))
00750         return;
00751     ScCore->setSplashStatus( QObject::tr("Reading Font Cache") );
00752     QTextStream ts(&f);
00753     ts.setCodec("UTF-8");
00754     QString errorMsg;
00755     int errorLine = 0, errorColumn = 0;
00756     if( !docu.setContent(ts.readAll(), &errorMsg, &errorLine, &errorColumn) )
00757     {
00758         f.close();
00759         return;
00760     }
00761     f.close();
00762     QDomElement elem = docu.documentElement();
00763     if (elem.tagName() != "CachedFonts")
00764         return;
00765     QDomNode DOC = elem.firstChild();
00766     while(!DOC.isNull())
00767     {
00768         QDomElement dc = DOC.toElement();
00769         if (dc.tagName()=="Font")
00770         {
00771             foCache.isChecked = false;
00772             foCache.isOK = static_cast<bool>(dc.attribute("Status", "1").toInt());
00773             foCache.lastMod = QDateTime::fromString(dc.attribute("Modified"), Qt::ISODate);
00774             checkedFonts.insert(dc.attribute("File"), foCache);
00775         }
00776         DOC = DOC.nextSibling();
00777     }
00778 }
00779 
00780 void SCFonts::WriteCacheList(QString pf)
00781 {
00782     QDomDocument docu("fontcacherc");
00783     QString st="<CachedFonts></CachedFonts>";
00784     docu.setContent(st);
00785     QDomElement elem = docu.documentElement();
00786     QMap<QString, testCache>::Iterator it;
00787     for (it = checkedFonts.begin(); it != checkedFonts.end(); ++it)
00788     {
00789         if (it.value().isChecked)
00790         {
00791             QDomElement fosu = docu.createElement("Font");
00792             fosu.setAttribute("File",it.key());
00793             fosu.setAttribute("Status",static_cast<int>(it.value().isOK));
00794             fosu.setAttribute("Modified",it.value().lastMod.toString(Qt::ISODate));
00795             elem.appendChild(fosu);
00796         }
00797     }
00798     ScCore->setSplashStatus( QObject::tr("Writing updated Font Cache") );
00799     QFile f(pf + "/checkfonts.xml");
00800     if(f.open(QIODevice::WriteOnly))
00801     {
00802         QTextStream s(&f);
00803         s.setCodec("UTF-8");
00804         s<<docu.toString();
00805         f.close();
00806     }
00807     checkedFonts.clear();
00808 }
00809 
00810 void SCFonts::GetFonts(QString pf, bool showFontInfo)
00811 {
00812     showFontInformation=showFontInfo;
00813     FontPath.clear();
00814     ReadCacheList(pf);
00815     ScCore->setSplashStatus( QObject::tr("Searching for Fonts") );
00816     AddUserPath(pf);
00817     // Search the system paths
00818     QStringList ftDirs = ScPaths::getSystemFontDirs();
00819     for (int i = 0; i < ftDirs.count(); i++)
00820         AddScalableFonts( ftDirs[i] );
00821     // Search Scribus font path
00822     if (!ScPaths::instance().fontDir().isEmpty() && QDir(ScPaths::instance().fontDir()).exists())
00823         AddScalableFonts( ScPaths::instance().fontDir() );
00824 // if fontconfig is there, it does all the work
00825 #if HAVE_FONTCONFIG
00826     // Search fontconfig paths
00827     QStringList::iterator fpi, fpend = FontPath.end();
00828     for(fpi = FontPath.begin() ; fpi != fpend; ++fpi) 
00829         AddScalableFonts(*fpi);
00830     AddFontconfigFonts();
00831 #else
00832 // on X11 look there:
00833 #ifdef Q_WS_X11
00834     AddXFontPath();
00835     AddXFontServerPath();
00836 #endif
00837 // add user and X11 fonts:
00838     QStringList::iterator fpi, fpend = FontPath.end();
00839     for(fpi = FontPath.begin() ; fpi != fpend; ++fpi) 
00840         AddScalableFonts(*fpi);
00841 #endif
00842     updateFontMap();
00843     WriteCacheList(pf);
00844 }
Created with personalized Doxygen. This is documentation for GPL software Scribus - Open Source Desktop Publishing.