Subversion Repositories Scribus

Rev

Rev 11143 | Rev 14609 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3 paul 1
/*
4430 cbradney 2
For general Scribus (>=1.3.2) copyright and licensing information please refer
3
to the COPYING file provided with the program. Following this notice may exist
4
a copyright and/or license notice that predates the release of Scribus 1.3.2
5
for which a new license (GPL+exception) is in place.
6
*/
7
/*
3 paul 8
        Scribus font handling code - copyright (C) 2001 by
9
        Alastair M. Robinson
10
 
220 Franz 11
        Based on code by Christian Tpp and Franz Schmid.
3 paul 12
 
13
        Contributed to the Scribus project under the terms of
14
        the GNU General Public License version 2, or any later
15
        version, at your discretion.
16
*/
17
 
1669 craig 18
#include <qglobal.h>
3 paul 19
#include <qapplication.h>
20
#include <qfile.h>
21
#include <qfileinfo.h>
22
#include <qstrlist.h>
23
#include <qstring.h>
24
#include <qtextstream.h>
25
#include <qfont.h>
26
#include <qdict.h>
27
#include <qmap.h>
68 Franz 28
#include <qdir.h>
1669 craig 29
#include <qregexp.h>
30
 
3 paul 31
#include <cstdlib>
32
#include "scfonts.h"
33
#include "scfonts_ttf.h"
2529 craig 34
#include "scfontmetrics.h"
494 fschmid 35
 
2856 cbradney 36
#include "prefsmanager.h"
2510 craig 37
#include "prefsfile.h"
38
#include "prefscontext.h"
39
#include "prefstable.h"
3566 fschmid 40
#include "scribus.h"
12813 jghali 41
#include "scribusapp.h"
2529 craig 42
#ifdef Q_WS_X11
43
#include <X11/X.h>
44
#include <X11/Xlib.h>
45
#endif
46
 
494 fschmid 47
#ifdef HAVE_FONTCONFIG
48
#include <fontconfig/fontconfig.h>
49
#endif
50
 
3794 cbradney 51
#include "scpaths.h"
2534 craig 52
#include "util.h"
53
 
2295 cbradney 54
#include FT_TRUETYPE_TAGS_H
55
#include FT_TRUETYPE_TABLES_H
56
 
5505 avox 57
 
58
 
59
/// copied from Freetype's FT_Stream_ReadAt()
60
FT_Error ftIOFunc( FT_Stream stream, unsigned long pos, unsigned char* buffer, unsigned long count)
61
{
62
        FT_Error  error = FT_Err_Ok;
63
        FT_ULong  read_bytes;
64
 
65
        if ( pos >= stream->size )
66
        {
67
                qDebug( "ftIOFunc: invalid i/o; pos = 0x%lx, size = 0x%lx\n",
68
                                   pos, stream->size );
69
 
70
                return FT_Err_Invalid_Stream_Operation;
71
        }
72
 
73
        if ( stream->read )
74
                read_bytes = stream->read( stream, pos, buffer, count );
75
        else
76
        {
77
                read_bytes = stream->size - pos;
78
                if ( read_bytes > count )
79
                        read_bytes = count;
80
 
81
                memcpy( buffer, stream->base + pos, read_bytes );
82
        }
83
 
84
        stream->pos = pos + read_bytes;
85
 
86
        if ( read_bytes < count )
87
        {
88
                qDebug( "ftIOFunc: invalid read; expected %lu bytes, got %lu\n",
89
                        count, read_bytes );
90
 
91
                error = FT_Err_Invalid_Stream_Operation;
92
        }
93
 
94
        return error;
95
}
96
 
97
 
98
 
99
 
3559 fschmid 100
Foi::Foi(QString fam, QString sty, QString alt, QString psname, QString path, int face, bool embedps)
3 paul 101
{
68 Franz 102
        isOTF = false;
103
        Subset = false;
2295 cbradney 104
        typeCode = Foi::UNKNOWN_TYPE;
105
        formatCode = Foi::UNKNOWN_FORMAT;
3559 fschmid 106
        SCName = alt;
107
        Family = fam;
108
        Effect = sty;
109
        cached_RealName = psname;
110
        fontFile = path;
111
        faceIndex_ = face;
112
        EmbedPS = embedps;
113
        Alternative = "";
3 paul 114
}
115
 
3544 avox 116
 
5018 avox 117
FT_Face ftFace() {
3544 avox 118
        // dummy for now
119
        return NULL;
120
}
121
 
3 paul 122
QString Foi::RealName()
123
{
3559 fschmid 124
        return cached_RealName;
3 paul 125
}
126
 
127
bool Foi::EmbedFont(QString &str)
128
{
129
        str+="Base";
2295 cbradney 130
        return(false);
3 paul 131
}
132
 
133
bool Foi::ReadMetrics()
134
{
135
        HasMetrics=false;
136
        for(int i=0;i<256;++i)
137
                CharWidth[i]=0;
138
        return(false);
139
}
140
 
141
bool Foi::GlNames(QMap<uint, QString> *GList)
142
{
2295 cbradney 143
        return GlyNames(this, GList);
3 paul 144
}
2295 cbradney 145
 
146
void Foi::RawData(QByteArray & bb)
147
{
148
        FT_Library library;
9560 avox 149
        FT_Face    face = NULL;
2295 cbradney 150
        bool       error;
151
 
152
        error = FT_Init_FreeType( &library );
153
        if (error)
3240 fschmid 154
                sDebug(QObject::tr("Freetype2 library not available"));
2295 cbradney 155
        else
3544 avox 156
                error = FT_New_Face( library, fontFile, faceIndex_, &face );
2295 cbradney 157
        if (error)
3544 avox 158
                sDebug(QObject::tr("Font %1 is broken, no embedding").arg(fontFile));
2295 cbradney 159
        else
160
        {
161
                FT_Stream fts = face->stream;
162
                bb.resize(fts->size);
5505 avox 163
                error = ftIOFunc(fts, 0L, reinterpret_cast<FT_Byte *>(bb.data()), fts->size);
2295 cbradney 164
                if (error)
165
                {
3544 avox 166
                        sDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(fontFile));
2295 cbradney 167
                        bb.resize(0);
168
                }
169
                /*
170
                if (showFontInformation)
171
                {
3544 avox 172
                        QFile f(fontFile);
173
                        qDebug(QObject::tr("RawData for Font %1(%2): size=%3 filesize=%4").arg(fontFile).arg(faceIndex_).arg(bb.size()).arg(f.size()));
2295 cbradney 174
                }
175
                */
176
        }
177
        FT_Done_Face(face);
178
        FT_Done_FreeType(library);
179
}
180
 
181
 
68 Franz 182
/*
183
void Foi::FontBez()
184
{
185
        FT_Face face;
186
        FT_Library library;
187
        QString ts;
188
        QPixmap pm(200, 100);
189
        bool error;
190
        int  pen_x;
191
        int YPos = qApp->font().pointSize();
192
        uint n;
193
        error = FT_Init_FreeType( &library );
3544 avox 194
        error = FT_New_Face( library, fontFile, 0, &face );
68 Franz 195
        ts = QString(face->family_name) + " " + QString(face->style_name);
196
        pm.fill();
197
        pen_x = 0;
198
        for (n = 0; n < ts.length(); n++)
199
                {
200
                uint dv = ts[n].unicode();
201
                error = FT_Set_Char_Size(       face, 0, qApp->font().pointSize()*64, 72, 72 );
202
                FT_Load_Char(face, dv, FT_LOAD_RENDER | FT_LOAD_NO_BITMAP | FT_LOAD_MONOCHROME);
203
                QByteArray bd(face->glyph->bitmap.rows * face->glyph->bitmap.pitch);
204
                uint yy = 0;
205
                uint adv;
206
                if ((face->glyph->bitmap.width % 8) == 0)
207
                        adv = face->glyph->bitmap.width / 8;
208
                else
209
                        adv = face->glyph->bitmap.width / 8 + 1;
210
                for (int y = 0; y < face->glyph->bitmap.rows; ++y)
211
                        {
212
                        memcpy(bd.data()+yy, face->glyph->bitmap.buffer+(y * face->glyph->bitmap.pitch), adv);
213
                        yy += adv;
214
                        }
215
                QBitmap bb(face->glyph->bitmap.width, face->glyph->bitmap.rows, (uchar*)bd.data(), false);
216
                QPixmap pixm(face->glyph->bitmap.width, face->glyph->bitmap.rows);
217
                if (!pixm.isNull())
218
                        {
219
                        pixm.fill(Qt::black);
220
                        pixm.setMask(bb);
221
                        QPainter p;
222
                        p.begin(&pm);
223
                        p.drawPixmap(pen_x+face->glyph->bitmap_left, YPos-face->glyph->bitmap_top, pixm);
224
                        p.end();
225
                        }
226
                pen_x += face->glyph->advance.x >> 6;
227
                }
228
        int high = qApp->fontMetrics().height();
229
        QPixmap pm2(pen_x, high);
230
        bitBlt(&pm2, 0, 0, &pm, 0, 0, pen_x, high);
231
        Appearance = pm2;
232
        FT_Done_FreeType( library );
233
        return;
234
}    */
3 paul 235
 
236
/*
237
        Class Foi_postscript
3142 cbradney 238
        Subclass of Foi, for PostScript fonts that could possibly have a .afm file
3 paul 239
        associated with them for metrics information.
240
*/
241
 
242
class Foi_postscript : public Foi
243
{
244
        public:
3544 avox 245
                Foi_postscript(QString fam, QString sty, QString alt, QString psname, QString path, int face, bool embedps) :
246
                Foi(fam,sty,alt,psname,path,face,embedps), metricsread(false)
3 paul 247
                {
248
                        HasMetrics=false;
249
                        HasKern = false;
250
                        Ascent = "0";
251
                        CapHeight = "0";
252
                        Descender = "0";
253
                        ItalicAngle = "0";
254
                        StdVW = "1";
255
                        FontBBox = "0 0 0 0";
256
                        IsFixedPitch = false;
2295 cbradney 257
                        typeCode = TYPE1;
3 paul 258
                        HasMetrics=true;
259
                }
260
 
261
                virtual QString RealName()
262
                {
3544 avox 263
                        return(Foi::RealName());
3 paul 264
                }
265
 
11143 jghali 266
                QStringList findFontMetrics(const QString& fontPath) const
267
                {
268
                        QStringList metricsFiles;
269
                        QFileInfo fi(fontPath);
270
 
271
                        QString fontDir  = fi.absFilePath();
272
                        QString fontFile = fi.fileName();
273
 
274
                        metricsFiles += findFontMetrics(fontDir, fontFile);
275
 
276
                        //if no metrics found look in afm and pfm subdirs
277
                        if ( metricsFiles.size() <= 0 )
278
                        {
279
                                QDir dir;
280
                                if (dir.exists(fontDir + "/AFMs"))
281
                                        metricsFiles += findFontMetrics(fontDir + "/AFMs", fontFile);
282
                                if (metricsFiles.size() <= 0 && dir.exists(fontDir + "/afm"))
283
                                        metricsFiles += findFontMetrics(fontDir + "/afm", fontFile);
284
                                if (metricsFiles.size() <= 0 && dir.exists(fontDir + "/Pfm"))
285
                                        metricsFiles += findFontMetrics(fontDir + "/Pfm", fontFile);
286
                                if (metricsFiles.size() <= 0 && dir.exists(fontDir + "/pfm"))
287
                                        metricsFiles += findFontMetrics(fontDir + "/pfm", fontFile);
288
                        }
289
 
290
                        return metricsFiles;
291
                }
292
 
293
                QStringList findFontMetrics(const QString& baseDir, const QString& baseName) const
294
                {
295
                        QStringList metricsFiles;
296
                        QString     basePath = baseDir + "/" + baseName;
297
                        QString     afnm = basePath.left(basePath.length()-3);
298
 
299
                        // Look for afm files
300
                        QString afmName(afnm+"afm");
301
                        if(QFile::exists(afmName))
302
                                metricsFiles.append(afmName);
303
                        else
304
                        {
305
                                afmName = afnm+"Afm";
306
                                if(QFile::exists(afmName))
307
                                        metricsFiles.append(afmName);
308
                                else
309
                                {
310
                                        afmName = afnm+"AFM";
311
                                        if(QFile::exists(afmName))
312
                                                metricsFiles.append(afmName);
313
                                }
314
                        }
315
 
316
                        // Look for pfm files
317
                        QString pfmName(afnm+"pfm");
318
                        if(QFile::exists(pfmName))
319
                                metricsFiles.append(pfmName);
320
                        else
321
                        {
322
                                pfmName = afnm+"Pfm";
323
                                if(QFile::exists(pfmName))
324
                                        metricsFiles.append(pfmName);
325
                                else
326
                                {
327
                                        afmName = afnm+"PFM";
328
                                        if(QFile::exists(pfmName))
329
                                                metricsFiles.append(pfmName);
330
                                }
331
                        }
332
 
333
                        return metricsFiles;
334
                }
335
 
336
                bool loadFontMetrics(FT_Face face, const QString& fontPath) const
337
                {
338
                        bool metricsFound = false;
339
                        QStringList fontMetrics = findFontMetrics(fontPath);
340
                        if (fontMetrics.size() > 0)
341
                        {
342
                                bool brokenMetric = false;
343
                                QString metricsFile;
344
                                for (uint i = 0; i < fontMetrics.size(); ++i)
345
                                {
346
                                        metricsFile = fontMetrics[i];
347
                                        if (FT_Attach_File(face, metricsFile.local8Bit().data()))
348
                                        {
349
                                                qDebug(QObject::tr("Font %1 has broken metrics in file %2, ignoring metrics").arg(fontPath).arg(metricsFile).latin1());
350
                                                brokenMetric = true;
351
                                        }
352
                                        else
353
                                        {
354
                                                if (brokenMetric)
355
                                                        qDebug(QObject::tr("Valid metrics were found for font %1, using metrics in file %2").arg(fontFilePath()).arg(metricsFile).latin1());
356
                                                metricsFound = true;
357
                                                break;
358
                                        }
359
                                }
360
                        }
361
                        /*else
362
                                qDebug(QObject::tr("No metrics found for font %1, ignoring font").arg(fontPath).latin1());*/
363
                        return metricsFound;
364
                }
365
 
3 paul 366
                virtual bool ReadMetrics()  // routine by Franz Schmid - modified by Alastair M. Robinson
367
                {
368
                        if(metricsread)
369
                                return(HasMetrics);
370
                        CharWidth.clear();
68 Franz 371
                        GlyphArray.clear();
84 Franz 372
                        QString tmp, tmp2, tmp3, tmp4;
80 Franz 373
                        double x, y;
68 Franz 374
                        FPointArray outlines;
375
                        struct GlyphR GRec;
3 paul 376
                        bool                    error;
377
                        FT_Library library;
378
                        FT_ULong  charcode;
379
                        FT_UInt   gindex;
380
                        FT_Face   face;
220 Franz 381
                        isStroked = false;
3 paul 382
                        error = FT_Init_FreeType( &library );
383
                        if (error)
391 Franz 384
                        {
3 paul 385
                                UseFont = false;
3500 avox 386
                                sDebug(QObject::tr("Font %1 is broken (FreeType2), discarding it").arg(fontPath()));
3 paul 387
                                return false;
391 Franz 388
                        }
3544 avox 389
                        error = FT_New_Face( library, fontFilePath(), faceIndex(), &face );
3 paul 390
                        if (error)
391 Franz 391
                        {
3 paul 392
                                UseFont = false;
3500 avox 393
                                sDebug(QObject::tr("Font %1 is broken (no Face), discarding it").arg(fontPath()));
2295 cbradney 394
                                FT_Done_FreeType( library );
3 paul 395
                                return false;
391 Franz 396
                        }
80 Franz 397
                        uniEM = static_cast<double>(face->units_per_EM);
3500 avox 398
                        QString afnm = fontFilePath().left(fontFilePath().length()-3);
11143 jghali 399
                        error = loadFontMetrics(face, fontFilePath()) ? 0 : 1;
3 paul 400
                        HasKern = FT_HAS_KERNING(face);
401
                        Ascent = tmp.setNum(face->ascender);
402
                        Descender = tmp.setNum(face->descender);
68 Franz 403
                        numDescender = face->descender / uniEM;
404
                        numAscent = face->ascender / uniEM;
405
                        underline_pos = face->underline_position / uniEM;
406
                        strikeout_pos = numAscent / 3;
407
                        strokeWidth = face->underline_thickness / uniEM;
3 paul 408
                        CapHeight = Ascent;
409
                        ItalicAngle = "0";
410
                        StdVW = "1";
84 Franz 411
                        FontBBox = tmp.setNum(face->bbox.xMin)+" "+tmp2.setNum(face->bbox.yMin)+" "+tmp3.setNum(face->bbox.xMax)+" "+tmp4.setNum(face->bbox.yMax);
3 paul 412
                        IsFixedPitch = face->face_flags & 4;
896 fschmid 413
                        setBestEncoding(face);
3 paul 414
                        gindex = 0;
415
                        charcode = FT_Get_First_Char( face, &gindex );
2295 cbradney 416
                        int goodGlyph = 0;
417
                        int invalidGlyph = 0;
3 paul 418
                        while ( gindex != 0 )
391 Franz 419
                        {
220 Franz 420
                                error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
421
                                if (error)
391 Franz 422
                                {
2295 cbradney 423
                                        ++invalidGlyph;
3500 avox 424
                                        sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(fontPath()).arg(gindex).arg(charcode));
2394 cbradney 425
                                        charcode = FT_Get_Next_Char( face, charcode, &gindex );
426
                                        continue;
391 Franz 427
                                }
2295 cbradney 428
                                ++goodGlyph;
220 Franz 429
                                double ww = face->glyph->metrics.horiAdvance / uniEM;
430
                                if (face->glyph->format == FT_GLYPH_FORMAT_PLOTTER)
431
                                        isStroked = true;
432
                                error = false;
433
                                outlines = traceChar(face, charcode, 10, &x, &y, &error);
434
                                if (!error)
391 Franz 435
                                {
220 Franz 436
                                        CharWidth.insert(charcode, ww);
437
                                        GRec.Outlines = outlines.copy();
438
                                        GRec.x = x;
439
                                        GRec.y = y;
440
                                        GlyphArray.insert(charcode, GRec);
391 Franz 441
                                }
3 paul 442
                                charcode = FT_Get_Next_Char( face, charcode, &gindex );
391 Franz 443
                        }
2295 cbradney 444
                        FT_Done_Face( face );
3 paul 445
                        FT_Done_FreeType( library );
2394 cbradney 446
                        if (invalidGlyph > 0) {
447
                                UseFont = false;
3500 avox 448
                                sDebug(QObject::tr("Font %1 is broken and will be discarded").arg(fontPath()));
3240 fschmid 449
                        }
220 Franz 450
                        HasMetrics=UseFont;
451
                        metricsread=UseFont;
3 paul 452
                        return(HasMetrics);
453
                }
454
        private:
455
                bool metricsread;
456
};
457
 
458
/*
459
        Class Foi_pfb
460
        Subclass of Foi, specifically for Adobe type 1 .pfb fonts.
461
        Implements: RealName() and EmbedFont().
462
*/
463
 
464
class Foi_pfb : public Foi_postscript
465
{
466
        public:
3544 avox 467
                Foi_pfb(QString fam, QString sty, QString alt, QString psname, QString path, int face, bool embedps) :
468
                Foi_postscript(fam,sty,alt,psname,path,face,embedps)
3 paul 469
                {
2295 cbradney 470
                        formatCode = PFB;
3 paul 471
                }
472
 
473
                virtual bool EmbedFont(QString &str)
474
                {
2295 cbradney 475
                        QByteArray bb;
476
                        RawData(bb);
3 paul 477
                        QString tmp2 = "";
2295 cbradney 478
                        if ((bb.size() > 2) &&  (bb[0] == char(0x80)) && (static_cast<int>(bb[1]) == 1))
3 paul 479
                        {
2295 cbradney 480
                                QString tmp3="";
481
                                QString tmp4 = "";
482
                                uint posi,cxxc=0;
483
                                for (posi = 6; posi < bb.size(); ++posi)
3 paul 484
                                {
2295 cbradney 485
                                        if ((bb[posi] == char(0x80)) && (posi+1 < bb.size()) && (static_cast<int>(bb[posi+1]) == 2))
486
                                                break;
487
                                        str += bb[posi];
488
                                }
489
                                uint ulen;
490
                                if (posi+6 < bb.size())
491
                                {
3 paul 492
                                        ulen = bb[posi+2] & 0xff;
493
                                        ulen |= (bb[posi+3] << 8) & 0xff00;
494
                                        ulen |= (bb[posi+4] << 16) & 0xff0000;
495
                                        ulen |= (bb[posi+5] << 24) & 0xff000000;
496
                                        posi += 6;
2295 cbradney 497
                                        if (posi + ulen > bb.size())
498
                                                ulen = bb.size() - posi - 1;
3 paul 499
                                        char linebuf[80];
500
                                        cxxc=0;
501
                                        for (uint j = 0; j < ulen; ++j)
502
                                        {
503
                                                unsigned char u=bb[posi];
504
                                                linebuf[cxxc]=((u >> 4) & 15) + '0';
505
                                                if(u>0x9f) linebuf[cxxc]+='a'-':';
506
                                                ++cxxc;
507
                                                u&=15; linebuf[cxxc]=u + '0';
508
                                                if(u>0x9) linebuf[cxxc]+='a'-':';
509
                                                ++posi;
510
                                                ++cxxc;
511
                                                if (cxxc > 72)
512
                                                {
513
                                                        linebuf[cxxc++]='\n';
514
                                                        linebuf[cxxc++]=0;
515
                                                        str += linebuf;
516
                                                        cxxc = 0;
517
                                                }
518
                                        }
519
                                        linebuf[cxxc]=0;
520
                                        str += linebuf;
521
                                        str += "\n";
522
                                }
2295 cbradney 523
                                posi += 6;
524
                                for (uint j = posi; j < bb.size(); ++j)
525
                                {
526
                                        if ((bb[j] == static_cast<char>(0x80)) && (j+1 < bb.size()) && (static_cast<int>(bb[j+1]) == 3))
527
                                                break;
528
                                        if(bb[j]=='\r')
529
                                                str+="\n";
530
                                        else
531
                                                str += bb[j];
532
                                }
533
                                str += "\n";
534
                                cxxc = 0;
535
                                return true;
3 paul 536
                        }
2295 cbradney 537
                        else
538
                        {
3500 avox 539
                                sDebug(QObject::tr("Font %1 cannot be read, no embedding").arg(fontPath()));
2295 cbradney 540
                                return false;
541
                        }
3 paul 542
                }
543
};
544
 
545
/*
546
        Class Foi_pfa
547
        Subclass of Foi, specifically for Adobe type 1 and type 3 .pfa fonts.
548
        Implements: RealName() and EmbedFont().
549
*/
550
 
551
class Foi_pfa : public Foi_postscript
552
{
553
        public:
3544 avox 554
                Foi_pfa(QString fam, QString sty, QString alt, QString psname, QString path, int face, bool embedps) :
555
                Foi_postscript(fam,sty,alt,psname,path,face,embedps)
3 paul 556
                {
2295 cbradney 557
                        formatCode = PFA;
3 paul 558
                }
559
                virtual bool EmbedFont(QString &str)
560
                {
2295 cbradney 561
                        QByteArray bb;
562
                        RawData(bb);
563
                        if (bb.size() > 2 && bb[0] == '%' && bb[1] == '!')
564
                        {
565
                                // this is ok since bb will not contain '\0'
566
                                str.append(bb);
567
                                return true;
568
                        }
569
                        return false;
3 paul 570
                }
571
};
572
 
573
 
2295 cbradney 574
 
3 paul 575
/***************************************************************************/
576
 
3559 fschmid 577
SCFonts::SCFonts() : QDict<Foi>(), FontPath(true)
578
{
579
        setAutoDelete(true);
580
        showFontInformation=false;
581
        checkedFonts.clear();
582
}
583
 
3 paul 584
SCFonts::~SCFonts()
585
{
586
}
587
 
2508 fschmid 588
void SCFonts::updateFontMap()
589
{
590
        fontMap.clear();
591
        SCFontsIterator it( *this );
592
        for ( ; it.current(); ++it)
593
        {
594
                if (it.current()->UseFont)
595
                {
3544 avox 596
                        if (fontMap.contains(it.current()->family()))
2508 fschmid 597
                        {
598
                                QStringList effect;
3544 avox 599
                                if (!fontMap[it.current()->family()].contains(it.current()->style()))
2508 fschmid 600
                                {
3544 avox 601
                                        fontMap[it.current()->family()].append(it.current()->style());
2508 fschmid 602
                                }
603
                        }
604
                        else
605
                        {
606
                                QStringList effect;
3544 avox 607
                                effect.append(it.current()->style());
608
                                fontMap.insert(it.current()->family(), effect);
2508 fschmid 609
                        }
610
                }
611
        }
612
}
613
 
3 paul 614
/* Add a path to the list of fontpaths, ensuring that
615
   a trailing slash is present.
616
   Checks to make sure this path is not already present
617
   before adding.
618
*/
619
void SCFonts::AddPath(QString p)
620
{
621
        if(p.right(1) != "/")
622
          p += "/";
623
        if(FontPath.find(p)==-1)
624
                FontPath.insert(FontPath.count(),p);
625
}
626
 
494 fschmid 627
void SCFonts::AddScalableFonts(const QString &path, QString DocName)
3 paul 628
{
3831 cbradney 629
        //Make sure this is not empty or we will scan the whole drive on *nix
630
        //QString::null+/ is / of course.
631
        if (path.isEmpty())
632
                return;
494 fschmid 633
        FT_Library library = NULL;
12813 jghali 634
        QString pathfile, fullpath;
68 Franz 635
        bool error;
3566 fschmid 636
        error = FT_Init_FreeType( &library );
3831 cbradney 637
        QString pathname(path);
3830 cbradney 638
        if ( !pathname.endsWith("/") )
639
                pathname += "/";
640
        pathname=QDir::convertSeparators(pathname);
641
        QDir d(pathname, "*", QDir::Name, QDir::Dirs | QDir::Files | QDir::Readable);
68 Franz 642
        if ((d.exists()) && (d.count() != 0))
494 fschmid 643
        {
644
                for (uint dc = 0; dc < d.count(); ++dc)
3 paul 645
                {
2919 craig 646
                        // readdir may return . or .., which we don't want to recurse
647
                        // over. Skip 'em.
648
                        if (d[dc] == "." || d[dc] == "..")
649
                                continue;
12813 jghali 650
                        fullpath = pathname+d[dc];
3830 cbradney 651
                        QFileInfo fi(pathname+d[dc]);
84 Franz 652
                        if (!fi.exists())      // Sanity check for broken Symlinks
653
                                continue;
2295 cbradney 654
 
655
                        qApp->processEvents();
656
 
12813 jghali 657
                        bool symlink = fi.isSymLink();
658
                        if (symlink)
494 fschmid 659
                        {
84 Franz 660
                                QFileInfo fi3(fi.readLink());
661
                                if (fi3.isRelative())
3830 cbradney 662
                                        pathfile = pathname+fi.readLink();
84 Franz 663
                                else
664
                                        pathfile = fi3.absFilePath();
494 fschmid 665
                        }
84 Franz 666
                        else
12813 jghali 667
                                pathfile = fullpath;
84 Franz 668
                        QFileInfo fi2(pathfile);
2295 cbradney 669
                        if (fi2.isDir())
670
                        {
12813 jghali 671
                                if (symlink)
672
                                {
673
                                        // Check if symlink points to a parent directory
674
                                        // in order to avoid infinite recursion
675
                                        QString fullpath2 = fullpath, pathfile2 = pathfile;
676
                                        if (ScQApp->isWinGUI())
677
                                        {
678
                                                // Ensure both path use same separators on Windows
679
                                                // Arghhh!!! in Qt3 QFileInfo::absFilePath() may return old DOS-style paths
680
                                                fullpath2 = getShortPathName( QDir::convertSeparators(fullpath2) ).lower();
681
                                                pathfile2 = getShortPathName( QDir::convertSeparators(pathfile2) ).lower();
682
                                        }
683
                                        if (fullpath2.startsWith(pathfile2))
684
                                                continue;
685
                                }
2877 cbradney 686
                                if (DocName.isEmpty())
2295 cbradney 687
                                        AddScalableFonts(pathfile);
688
                                continue;
689
                        }
504 cbradney 690
                        QString ext = fi.extension(false).lower();
691
                        QString ext2 = fi2.extension(false).lower();
2877 cbradney 692
                        if ((ext != ext2) && (ext.isEmpty()))
693
                                ext = ext2;
2295 cbradney 694
                        if ((ext == "ttc") || (ext == "dfont") || (ext == "pfa") || (ext == "pfb") || (ext == "ttf") || (ext == "otf"))
414 Franz 695
                        {
2295 cbradney 696
                                error = AddScalableFont(pathfile, library, DocName);
414 Franz 697
                        }
2295 cbradney 698
#ifdef FT_MACINTOSH
2877 cbradney 699
                        else if (ext.isEmpty() && DocName.isEmpty())
2295 cbradney 700
                        {
701
                                error = AddScalableFont(pathfile, library, DocName);
702
                                if (error)
8379 avox 703
                                        error = AddScalableFont(pathfile + "/..namedfork/rsrc",library, DocName);
2295 cbradney 704
                        }
705
#endif                          
3 paul 706
                }
494 fschmid 707
        }
68 Franz 708
        FT_Done_FreeType( library );
3 paul 709
}
710
 
2295 cbradney 711
/**
712
 * tests magic words to determine the fontformat and preliminary fonttype
713
 */
714
void getFontFormat(FT_Face face, Foi::FontFormat & fmt, Foi::FontType & type)
494 fschmid 715
{
2295 cbradney 716
        static const char* T42_HEAD      = "%!PS-TrueTypeFont";
717
        static const char* T1_HEAD      = "%!FontType1";
718
        static const char* T1_ADOBE_HEAD = "%!PS-AdobeFont-1";
719
        static const char* PSFONT_ADOBE2_HEAD  = "%!PS-Adobe-2.0 Font";
720
        static const char* PSFONT_ADOBE21_HEAD  = "%!PS-Adobe-2.1 Font";
721
        static const char* PSFONT_ADOBE3_HEAD  = "%!PS-Adobe-3.0 Resource-Font";
2730 cbradney 722
        static const int   FONT_NO_ERROR = 0;
2295 cbradney 723
 
724
        const FT_Stream fts = face->stream;
725
        char buf[128];
726
 
727
        fmt = Foi::UNKNOWN_FORMAT;
728
        type = Foi::UNKNOWN_TYPE;
5505 avox 729
        if (ftIOFunc(fts, 0L, reinterpret_cast<FT_Byte *>(buf), 128) == FONT_NO_ERROR)
494 fschmid 730
        {
2295 cbradney 731
                if(strncmp(buf,T42_HEAD,strlen(T42_HEAD)) == 0)
1321 fschmid 732
                {
2295 cbradney 733
                        fmt = Foi::TYPE42;
734
                        type = Foi::TTF;
1321 fschmid 735
                }
2295 cbradney 736
                else if(strncmp(buf,T1_HEAD,strlen(T1_HEAD)) == 0 ||
737
                            strncmp(buf,T1_ADOBE_HEAD,strlen(T1_ADOBE_HEAD)) == 0)
1321 fschmid 738
                {
2295 cbradney 739
                        fmt = Foi::PFA;
740
                        type = Foi::TYPE1;
1321 fschmid 741
                }
2295 cbradney 742
                else if(strncmp(buf,PSFONT_ADOBE2_HEAD,strlen(PSFONT_ADOBE2_HEAD)) == 0 ||
743
                            strncmp(buf,PSFONT_ADOBE21_HEAD,strlen(PSFONT_ADOBE21_HEAD)) == 0 ||
744
                            strncmp(buf,PSFONT_ADOBE3_HEAD,strlen(PSFONT_ADOBE3_HEAD)) ==0)
1321 fschmid 745
                {
2295 cbradney 746
                        // Type2(CFF), Type0(Composite/CID), Type 3, Type 14 etc would end here
747
                        fmt = Foi::PFA;
748
                        type = Foi::UNKNOWN_TYPE;
1321 fschmid 749
                }
2295 cbradney 750
                else if(buf[0] == '\200' && buf[1] == '\1')
1321 fschmid 751
                {
2295 cbradney 752
                        fmt = Foi::PFB;
753
                        type = Foi::TYPE1;
1321 fschmid 754
                }
2295 cbradney 755
                else if(buf[0] == '\0' && buf[1] == '\1'
756
                                && buf[2] == '\0' && buf[3] == '\0')
494 fschmid 757
                {
2295 cbradney 758
                        fmt = Foi::SFNT;
759
                        type = Foi::TTF;
760
                }
761
                else if(strncmp(buf,"true",4) == 0)
762
                {
763
                        fmt = Foi::SFNT;
764
                        type = Foi::TTF;
765
                }
766
                else if(strncmp(buf,"ttcf",4) == 0)
767
                {
768
                        fmt = Foi::TTCF;
769
                        type = Foi::OTF;
770
                }
771
                else if(strncmp(buf,"OTTO",4) == 0)
772
                {
773
                        fmt = Foi::SFNT;
774
                        type = Foi::OTF;
775
                }
776
                // missing: raw CFF
777
        }
778
}
779
 
780
/**
781
 * Checks face, which must be sfnt based, for the subtype.
782
 * Possible values: TTF, CFF, OTF
783
 */
784
void getSFontType(FT_Face face, Foi::FontType & type)
785
{
786
        if (FT_IS_SFNT(face))
787
        {
788
                FT_ULong ret = 0;
789
                bool hasGlyph = ! FT_Load_Sfnt_Table(face, TTAG_glyf, 0, NULL,  &ret);
790
                hasGlyph &= ret > 0;
791
                bool hasCFF = ! FT_Load_Sfnt_Table(face, TTAG_CFF, 0, NULL,  &ret);
792
                hasCFF &= ret > 0;
793
                if (hasGlyph)
794
                        type = Foi::TTF;
795
                else if (hasCFF)
796
                        type = Foi::OTF;
797
                // TODO: CID or no
798
        }
799
}
800
 
801
// Load a single font into the library from the passed filename. Returns true on error.
802
bool SCFonts::AddScalableFont(QString filename, FT_Library &library, QString DocName)
803
{
3566 fschmid 804
        static bool firstRun;
3633 fschmid 805
        bool Subset = false;
806
        char *buf[50];
807
        QString glyName = "";
2295 cbradney 808
        Foi::FontFormat format;
809
        Foi::FontType   type;
810
        FT_Face         face = NULL;
3559 fschmid 811
        struct testCache foCache;
812
        QFileInfo fic(filename);
813
        foCache.isOK = false;
814
        foCache.isChecked = true;
815
        foCache.lastMod = fic.lastModified();
3566 fschmid 816
        if (checkedFonts.count() == 0)
817
        {
818
                firstRun = true;
4026 craig 819
                ScMW->setSplashStatus( QObject::tr("Creating Font Cache") );
3566 fschmid 820
        }
2295 cbradney 821
        bool error = FT_New_Face( library, filename, 0, &face );
822
        if (error)
823
        {
824
                if (face != NULL)
825
                        FT_Done_Face( face );
3559 fschmid 826
                checkedFonts.insert(filename, foCache);
5018 avox 827
                if (showFontInformation)
828
                        sDebug(QObject::tr("Font %1 is broken, discarding it").arg(filename));
2295 cbradney 829
                return true;
830
        }
831
        getFontFormat(face, format, type);
832
        if (format == Foi::UNKNOWN_FORMAT)
833
        {
3474 cbradney 834
                if (showFontInformation)
835
                        sDebug(QObject::tr("Failed to load font %1 - font type unknown").arg(filename));
3559 fschmid 836
                checkedFonts.insert(filename, foCache);
2295 cbradney 837
                error = true;
838
        }
3633 fschmid 839
        bool HasNames = FT_HAS_GLYPH_NAMES(face);
3469 fschmid 840
        if (!error)
841
        {
3559 fschmid 842
                if (!checkedFonts.contains(filename))
3469 fschmid 843
                {
3566 fschmid 844
                        if (!firstRun)
4026 craig 845
                                ScMW->setSplashStatus( QObject::tr("New Font found, checking...") );
3559 fschmid 846
                        FT_UInt gindex = 0;
847
                        FT_ULong charcode = FT_Get_First_Char( face, &gindex );
848
                        while ( gindex != 0 )
3469 fschmid 849
                        {
3559 fschmid 850
                                error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
851
                                if (error)
852
                                {
853
                                        if (showFontInformation)
854
                                                sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(filename).arg(gindex).arg(charcode));
855
                                        if (face != NULL)
856
                                                FT_Done_Face( face );
857
                                        checkedFonts.insert(filename, foCache);
858
                                        return true;
859
                                }
3633 fschmid 860
                                FT_Get_Glyph_Name(face, gindex, buf, 50);
861
                                QString newName = QString(reinterpret_cast<char*>(buf));
862
                                if (newName == glyName)
863
                                {
864
                                        HasNames = false;
865
                                        Subset = true;
866
                                }
867
                                glyName = newName;
3559 fschmid 868
                                charcode = FT_Get_Next_Char( face, charcode, &gindex );
869
                        }
870
                        foCache.isOK = true;
871
                        checkedFonts.insert(filename, foCache);
872
                }
873
                else
874
                {
875
                        if (!checkedFonts[filename].isOK)
876
                        {
877
                                checkedFonts[filename].isChecked = true;
3469 fschmid 878
                                return true;
879
                        }
3559 fschmid 880
                        if (checkedFonts[filename].lastMod != fic.lastModified())
881
                        {
4026 craig 882
                                ScMW->setSplashStatus( QObject::tr("Modified Font found, checking...") );
3559 fschmid 883
                                FT_UInt gindex = 0;
884
                                FT_ULong charcode = FT_Get_First_Char( face, &gindex );
885
                                while ( gindex != 0 )
886
                                {
887
                                        error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
888
                                        if (error)
889
                                        {
890
                                                if (showFontInformation)
891
                                                        sDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(filename).arg(gindex).arg(charcode));
892
                                                if (face != NULL)
893
                                                        FT_Done_Face( face );
894
                                                checkedFonts.insert(filename, foCache);
895
                                                return true;
896
                                        }
3633 fschmid 897
                                        FT_Get_Glyph_Name(face, gindex, buf, 50);
898
                                        QString newName = QString(reinterpret_cast<char*>(buf));
899
                                        if (newName == glyName)
900
                                        {
901
                                                HasNames = false;
902
                                                Subset = true;
903
                                        }
904
                                        glyName = newName;
3559 fschmid 905
                                        charcode = FT_Get_Next_Char( face, charcode, &gindex );
906
                                }
907
                                foCache.isOK = true;
908
                                checkedFonts[filename] = foCache;
909
                        }
910
                        else
911
                        {
912
                                checkedFonts[filename].isOK = true;
913
                                checkedFonts[filename].isChecked = true;
914
                        }
3469 fschmid 915
                }
916
        }
917
        int faceindex=0;
2295 cbradney 918
        while (!error)
919
        {
4343 cbradney 920
                QString fam(face->family_name);
921
                QString sty(face->style_name);
3460 fschmid 922
                if (sty == "Regular")
923
                {
924
                        switch (face->style_flags)
925
                        {
926
                                case 0:
927
                                        break;
928
                                case 1:
929
                                        sty = "Italic";
930
                                        break;
931
                                case 2:
932
                                        sty = "Bold";
933
                                        break;
934
                                case 3:
935
                                        sty = "Bold Italic";
936
                                        break;
937
                                default:
938
                                        break;
939
                        }
940
                }
4343 cbradney 941
                QString ts(fam + " " + sty);
942
                QString alt("");
3460 fschmid 943
                const char* psName = FT_Get_Postscript_Name(face);
944
                QString qpsName;
945
                if (psName)
946
                        qpsName = QString(psName);
947
                else
948
                        qpsName = ts;
2295 cbradney 949
                Foi *t = find(ts);
3460 fschmid 950
                if (t)
951
                {
3544 avox 952
                        if (t->RealName() != qpsName)
3460 fschmid 953
                        {
3544 avox 954
                                alt = " ("+qpsName+")";
955
                                ts += alt;
956
                                sty += alt;
3460 fschmid 957
                        }
958
                }
959
                t = find(ts);
2295 cbradney 960
                if (!t)
961
                {
962
                        switch (format)
963
                        {
964
                                case Foi::PFA:
3559 fschmid 965
                                        t = new Foi_pfa(fam, sty, ts, qpsName, filename, faceindex, true);
3633 fschmid 966
                                        t->Subset = Subset;
2295 cbradney 967
                                        break;
2508 fschmid 968
                                case Foi::PFB:
3559 fschmid 969
                                        t = new Foi_pfb(fam, sty, ts, qpsName, filename, faceindex, true);
3633 fschmid 970
                                        t->Subset = Subset;
2295 cbradney 971
                                        break;
972
                                case Foi::SFNT:
3559 fschmid 973
                                        t = new Foi_ttf(fam, sty, ts, qpsName, filename, faceindex, true);
2295 cbradney 974
                                        getSFontType(face, t->typeCode);
975
                                        if (t->typeCode == Foi::OTF)
976
                                        {
977
                                                t->isOTF = true;
978
                                                t->Subset = true;
979
                                        }
3633 fschmid 980
                                        else
981
                                                t->Subset = Subset;
2295 cbradney 982
                                        break;
983
                                case Foi::TTCF:
3559 fschmid 984
                                        t = new Foi_ttf(fam, sty, ts, qpsName, filename, faceindex, true);
2295 cbradney 985
                                        t->formatCode = Foi::TTCF;
986
                                        t->typeCode = Foi::TTF;
987
                                        //getSFontType(face, t->typeCode);
988
                                        if (t->typeCode == Foi::OTF)
989
                                        {
990
                                                t->isOTF = true;
991
                                                t->Subset = true;
992
                                        }
3633 fschmid 993
                                        else
994
                                                t->Subset = Subset;
2295 cbradney 995
                                        break;
996
                                case Foi::TYPE42:
3559 fschmid 997
                                        t = new Foi_ttf(fam, sty, ts, qpsName, filename, faceindex, true);
2295 cbradney 998
                                        getSFontType(face, t->typeCode);
999
                                        if (t->typeCode == Foi::OTF)
1000
                                        {
1001
                                                t->isOTF = true;
1002
                                                t->Subset = true;
1003
                                        }
3633 fschmid 1004
                                        else
1005
                                                t->Subset = Subset;
2295 cbradney 1006
                                        break;
4166 fschmid 1007
                                default:
1008
                                /* catching any types not handled above to silence compiler */
1009
                                        break;
2295 cbradney 1010
                        }
494 fschmid 1011
                        insert(ts,t);
3633 fschmid 1012
                        t->HasNames = HasNames;
494 fschmid 1013
                        t->EmbedPS = true;
1014
                        t->UseFont = true;
1015
                        t->CharWidth[13] = 0;
1016
                        t->CharWidth[28] = 0;
1017
                        t->CharWidth[9] = 1;
8493 fschmid 1018
                        if (face->num_glyphs > 2048)
6982 fschmid 1019
                                t->Subset = true;
494 fschmid 1020
                        t->PrivateFont = DocName;
2633 cbradney 1021
                        //setBestEncoding(face); //AV
2295 cbradney 1022
                        switch (face->charmap? face->charmap->encoding : -1)
1023
                        {
1024
                                case     FT_ENCODING_ADOBE_STANDARD:
1025
                                        t->FontEnc = QString("StandardEncoding");
1026
                                        break;
1027
                                case     FT_ENCODING_APPLE_ROMAN:
1028
                                        t->FontEnc = QString("MacRomanEncoding");
1029
                                        break;
1030
                                case     FT_ENCODING_ADOBE_EXPERT:
1031
                                        t->FontEnc = QString("MacExpertEncoding");
1032
                                        break;
1033
                                case     FT_ENCODING_ADOBE_LATIN_1:
1034
                                        t->FontEnc = QString("WinAnsiEncoding");
1035
                                        break;
1036
                                case     FT_ENCODING_UNICODE:
1037
                                        t->FontEnc = QString("Unicode");
1038
                                        break;
1039
                                default:
1040
                                        t->FontEnc = QString();
1041
                        }
1042
                        if (showFontInformation)
3544 avox 1043
                                sDebug(QObject::tr("Font %1 loaded from %2(%3)").arg(t->RealName()).arg(filename).arg(faceindex+1));
2295 cbradney 1044
 
1045
/*
1046
//debug
1047
                        QByteArray bb;
1048
                        t->RawData(bb);
1049
                        QFile dump(QString("/tmp/fonts/%1-%2").arg(ts).arg(psName));
1050
                        dump.open(IO_WriteOnly);
1051
                        QDataStream os(&dump);
1052
                        os.writeRawBytes(bb.data(), bb.size());
1053
                        dump.close();
1054
*/
494 fschmid 1055
                }
2295 cbradney 1056
                else
1057
                {
1058
                        if (showFontInformation)
3240 fschmid 1059
                                sDebug(QObject::tr("Font %1(%2) is duplicate of %3").arg(filename).arg(faceindex+1).arg(t->fontPath()));
2295 cbradney 1060
                        // this is needed since eg. AppleSymbols will happily return a face for *any* face_index
5018 avox 1061
                        if (faceindex > 0) {
1062
                                break;
1063
                        }
2295 cbradney 1064
                }
5018 avox 1065
                FT_Done_Face(face);
1066
                face=NULL;
1067
                ++faceindex;
1068
                error = FT_New_Face( library, filename, faceindex, &face );
2295 cbradney 1069
        } //while
1070
 
494 fschmid 1071
        if (face != 0)
1072
                FT_Done_Face( face );
4668 avox 1073
        return error && faceindex == 0;
494 fschmid 1074
}
1075
 
1076
void SCFonts::removeFont(QString name)
1077
{
1078
        remove(name);
2508 fschmid 1079
        updateFontMap();
494 fschmid 1080
}
1081
 
776 fschmid 1082
#ifdef HAVE_FONTCONFIG
1083
// Use Fontconfig to locate and load fonts.
1084
void SCFonts::AddFontconfigFonts()
1085
{
2295 cbradney 1086
        // All-in-one library setup. Perhaps this should be in
1087
        // the SCFonts constructor.
1088
        FcConfig* FcInitLoadConfigAndFonts();
1089
        // The pattern controls what fonts to match. In this case we want to
1090
        // match all scalable fonts, but ignore bitmap fonts.
1091
        FcPattern* pat = FcPatternBuild(NULL,
1092
                                                                        FC_SCALABLE, FcTypeBool, true,
1093
                                                                        NULL);
1094
        // The ObjectSet tells FontConfig what information about each match to return.
1095
        // We currently just need FC_FILE, but other info like font family and style
1096
        // is availible - see "man fontconfig".
1097
        FcObjectSet* os = FcObjectSetBuild (FC_FILE, (char *) 0);
1098
        // Now ask fontconfig to retrieve info as specified in 'os' about fonts
1099
        // matching pattern 'pat'.
1100
        FcFontSet* fs = FcFontList(0, pat, os);
1101
        FcObjectSetDestroy(os);
1102
        FcPatternDestroy(pat);
1103
        // Create the Freetype library
1104
        bool error;
1105
        FT_Library library = NULL;
1106
        error = FT_Init_FreeType( &library );
1107
        // Now iterate over the font files and load them
1108
        int i;
1109
        for (i = 0; i < fs->nfont; i++)
1110
        {
1111
                FcChar8 *file = NULL;
1112
                if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch)
1113
                {
1114
                        if (showFontInformation)
3240 fschmid 1115
                                sDebug(QObject::tr("Loading font %1 (found using fontconfig)").arg(QString((char*)file)));
2295 cbradney 1116
                        error = AddScalableFont(QString((char*)file), library, "");
1117
                }
1118
                else
1119
                        if (showFontInformation)
3240 fschmid 1120
                                sDebug(QObject::tr("Failed to load a font - freetype2 couldn't find the font file"));
2295 cbradney 1121
        }
1122
        FT_Done_FreeType( library );
776 fschmid 1123
}
1124
 
1125
#else
3794 cbradney 1126
#if !defined(QT_MAC) && !defined(_WIN32)
776 fschmid 1127
 
3 paul 1128
void SCFonts::AddXFontPath()
1129
{
1130
        int pathcount,i;
1131
        Display *display=XOpenDisplay(NULL);
1132
        char **fontpath=XGetFontPath(display,&pathcount);
1133
        for(i=0; i<pathcount; ++i)
1134
                AddPath(fontpath[i]);
1135
        XFreeFontPath(fontpath);
1136
}
1137
 
1138
/* replacement for AddXFontServerPath() for correctly parsing
1139
 * RedHad-Style /etc/X11/fs/config files */
1140
 
1141
void SCFonts::AddXFontServerPath()
1142
{
1143
        QFile fs("/etc/X11/fs/config");
1144
        if(!(fs.exists()))
1145
        {
1146
                fs.setName("/usr/X11R6/lib/X11/fs/config");
1147
                if(!(fs.exists()))
1148
                {
1149
                        fs.setName("/usr/X11/lib/X11/fs/config");
1150
                        if(!(fs.exists()))
1151
                                return;
1152
                }
1153
        }
1154
 
1155
        if (fs.open(IO_ReadOnly))
1156
        {
1157
                QString fsconfig,paths,tmp;
1158
                QTextStream tsx(&fs);
1159
                fsconfig = tsx.read();
1160
                fs.close();
1161
 
1162
                int pos = fsconfig.find("catalogue");
1163
                paths = fsconfig.mid(pos);
1164
                paths = paths.mid(paths.find("=")+1);
1165
 
1166
                pos=0;
1167
                do {
1168
                        pos = paths.find("\n",pos+1);
1169
                } while (pos > -1 && paths.mid(pos-1, 1) == ",");
1170
 
1171
                if(pos<0) pos=paths.length();
1172
                paths = paths.left(pos);
1173
                paths = paths.simplifyWhiteSpace();
1174
                paths.replace(QRegExp(" "), "");
1175
                paths.replace(QRegExp(","), "\n");
1176
                paths += "\n";
1177
                paths = paths.stripWhiteSpace();
1178
 
1179
                pos=-1;
1180
                do {
1181
                        int pos2;
1182
                        pos2 = paths.find("\n",pos+1);
1183
                        tmp = paths.mid(pos+1,(pos2-pos)-1);
1184
                        pos=pos2;
1185
 
1186
                        AddPath(tmp);
1187
 
1188
                } while (pos > -1);
1189
        }
1190
}
776 fschmid 1191
#endif
2295 cbradney 1192
#endif
3 paul 1193
 
2510 craig 1194
/* Add an extra path to our font search path,
1195
 * allowing a user to have extra fonts installed
1196
 * only for this user. Can also be used also as an emergency
1197
 * fallback if no suitable fonts are found elsewere */
3240 fschmid 1198
void SCFonts::AddUserPath(QString )
3 paul 1199
{
2856 cbradney 1200
        PrefsContext *pc = PrefsManager::instance()->prefsFile->getContext("Fonts");
2510 craig 1201
        PrefsTable *extraDirs = pc->getTable("ExtraFontDirs");
1202
        for (int i = 0; i < extraDirs->getRowCount(); ++i)
1203
                AddPath(extraDirs->get(i, 0));
3 paul 1204
}
1205
 
3559 fschmid 1206
void SCFonts::ReadCacheList(QString pf)
1207
{
3633 fschmid 1208
        QFile fr(pf + "/cfonts.xml");
1209
        QFileInfo fir(fr);
1210
        if (fir.exists())
1211
                fr.remove();
3559 fschmid 1212
        checkedFonts.clear();
1213
        struct testCache foCache;
1214
        QDomDocument docu("fontcacherc");
3633 fschmid 1215
        QFile f(pf + "/checkfonts.xml");
3559 fschmid 1216
        if(!f.open(IO_ReadOnly))
1217
                return;
4026 craig 1218
        ScMW->setSplashStatus( QObject::tr("Reading Font Cache") );
3559 fschmid 1219
        QTextStream ts(&f);
1220
        ts.setEncoding(QTextStream::UnicodeUTF8);
1221
        QString errorMsg;
1222
        int errorLine = 0, errorColumn = 0;
1223
        if( !docu.setContent(ts.read(), &errorMsg, &errorLine, &errorColumn) )
1224
        {
1225
                f.close();
1226
                return;
1227
        }
1228
        f.close();
1229
        QDomElement elem = docu.documentElement();
1230
        if (elem.tagName() != "CachedFonts")
1231
                return;
1232
        QDomNode DOC = elem.firstChild();
1233
        while(!DOC.isNull())
1234
        {
1235
                QDomElement dc = DOC.toElement();
1236
                if (dc.tagName()=="Font")
1237
                {
1238
                        foCache.isChecked = false;
4026 craig 1239
                        foCache.isOK = static_cast<bool>(dc.attribute("Status", "1").toInt());
3559 fschmid 1240
                        foCache.lastMod = QDateTime::fromString(dc.attribute("Modified"), Qt::ISODate);
1241
                        checkedFonts.insert(dc.attribute("File"), foCache);
1242
                }
1243
                DOC = DOC.nextSibling();
1244
        }
1245
}
1246
 
1247
void SCFonts::WriteCacheList(QString pf)
1248
{
1249
        QDomDocument docu("fontcacherc");
1250
        QString st="<CachedFonts></CachedFonts>";
1251
        docu.setContent(st);
1252
        QDomElement elem = docu.documentElement();
1253
        QMap<QString, testCache>::Iterator it;
1254
        for (it = checkedFonts.begin(); it != checkedFonts.end(); ++it)
1255
        {
1256
                if (it.data().isChecked)
1257
                {
1258
                        QDomElement fosu = docu.createElement("Font");
1259
                        fosu.setAttribute("File",it.key());
1260
                        fosu.setAttribute("Status",static_cast<int>(it.data().isOK));
1261
                        fosu.setAttribute("Modified",it.data().lastMod.toString(Qt::ISODate));
1262
                        elem.appendChild(fosu);
1263
                }
1264
        }
4026 craig 1265
        ScMW->setSplashStatus( QObject::tr("Writing updated Font Cache") );
3633 fschmid 1266
        QFile f(pf + "/checkfonts.xml");
3559 fschmid 1267
        if(f.open(IO_WriteOnly))
1268
        {
1269
                QTextStream s(&f);
1270
                s.setEncoding(QTextStream::UnicodeUTF8);
1271
                s<<docu.toString();
1272
                f.close();
1273
        }
1274
        checkedFonts.clear();
1275
}
1276
 
2295 cbradney 1277
void SCFonts::GetFonts(QString pf, bool showFontInfo)
3 paul 1278
{
2295 cbradney 1279
        showFontInformation=showFontInfo;
3 paul 1280
        FontPath.clear();
3559 fschmid 1281
        ReadCacheList(pf);
4026 craig 1282
        ScMW->setSplashStatus( QObject::tr("Searching for Fonts") );
3 paul 1283
        AddUserPath(pf);
3794 cbradney 1284
        // Search the system paths
1285
        QStringList ftDirs = ScPaths::getSystemFontDirs();
1286
        for (unsigned int i = 0; i < ftDirs.count(); i++)
1287
                AddScalableFonts( ftDirs[i] );
1288
        // Search Scribus font path
3831 cbradney 1289
        if (!ScPaths::instance().fontDir().isEmpty() && QDir(ScPaths::instance().fontDir()).exists())
3794 cbradney 1290
                AddScalableFonts( ScPaths::instance().fontDir() );
2295 cbradney 1291
// if fontconfig is there, it does all the work
1292
#if HAVE_FONTCONFIG
3794 cbradney 1293
        // Search fontconfig paths
776 fschmid 1294
        for(QStrListIterator fpi(FontPath) ; fpi.current() ; ++fpi)
1295
                AddScalableFonts(fpi.current());
1296
        AddFontconfigFonts();
1297
#else
2295 cbradney 1298
// on X11 look there:
1299
#ifdef Q_WS_X11
3 paul 1300
        AddXFontPath();
1301
        AddXFontServerPath();
2295 cbradney 1302
#endif
1303
// add user and X11 fonts:
1304
        for(QStrListIterator fpi(FontPath) ; fpi.current() ; ++fpi)
3 paul 1305
                AddScalableFonts(fpi.current());
494 fschmid 1306
#endif
2508 fschmid 1307
        updateFontMap();
3559 fschmid 1308
        WriteCacheList(pf);
494 fschmid 1309
}