Back to index

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