Subversion Repositories Scribus

Rev

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

Rev Author Line No. Line
3 paul 1
/*
2
        Scribus font handling code - copyright (C) 2001 by
3
        Alastair M. Robinson
4
 
220 Franz 5
        Based on code by Christian Tpp and Franz Schmid.
3 paul 6
 
7
        Contributed to the Scribus project under the terms of
8
        the GNU General Public License version 2, or any later
9
        version, at your discretion.
10
*/
11
 
1669 craig 12
#include <qglobal.h>
3 paul 13
#include <qapplication.h>
14
#include <qfile.h>
15
#include <qfileinfo.h>
16
#include <qstrlist.h>
17
#include <qstring.h>
18
#include <qtextstream.h>
19
#include <qfont.h>
20
#include <qdict.h>
21
#include <qmap.h>
68 Franz 22
#include <qdir.h>
1669 craig 23
#include <qregexp.h>
24
 
3 paul 25
#include <cstdlib>
26
#include "scfonts.h"
27
#include "scfonts_ttf.h"
2529 craig 28
#include "scfontmetrics.h"
494 fschmid 29
 
2510 craig 30
#include "prefsfile.h"
31
#include "prefscontext.h"
32
#include "prefstable.h"
33
 
2529 craig 34
#ifdef Q_WS_X11
35
#include <X11/X.h>
36
#include <X11/Xlib.h>
37
#endif
38
 
494 fschmid 39
#ifdef HAVE_FONTCONFIG
40
#include <fontconfig/fontconfig.h>
41
#endif
42
 
2534 craig 43
#include "util.h"
44
 
2295 cbradney 45
#include FT_INTERNAL_STREAM_H
46
#include FT_TRUETYPE_TAGS_H
47
#include FT_TRUETYPE_TABLES_H
48
 
2510 craig 49
extern PrefsFile* prefsFile;
3 paul 50
 
68 Franz 51
Foi::Foi(QString scname, QString path, bool embedps) :
2295 cbradney 52
        SCName(scname), Datei(path), faceIndex(0), EmbedPS(embedps)
3 paul 53
{
68 Franz 54
        isOTF = false;
55
        Subset = false;
2295 cbradney 56
        typeCode = Foi::UNKNOWN_TYPE;
57
        formatCode = Foi::UNKNOWN_FORMAT;
3 paul 58
}
59
 
60
QString Foi::RealName()
61
{
62
        QString result="Base";
63
        return(result);
64
}
65
 
66
bool Foi::EmbedFont(QString &str)
67
{
68
        str+="Base";
2295 cbradney 69
        return(false);
3 paul 70
}
71
 
72
bool Foi::ReadMetrics()
73
{
74
        HasMetrics=false;
75
        for(int i=0;i<256;++i)
76
                CharWidth[i]=0;
77
        return(false);
78
}
79
 
80
bool Foi::GlNames(QMap<uint, QString> *GList)
81
{
2295 cbradney 82
        return GlyNames(this, GList);
3 paul 83
}
2295 cbradney 84
 
85
void Foi::RawData(QByteArray & bb)
86
{
87
        FT_Library library;
88
        FT_Face    face;
89
        bool       error;
90
 
91
        error = FT_Init_FreeType( &library );
92
        if (error)
93
        {
94
                qDebug(QObject::tr("Freetype2 library not available"));
95
        }
96
        else
97
        {
98
                error = FT_New_Face( library, Datei, faceIndex, &face );
99
        }
100
        if (error)
101
        {
102
                qDebug(QObject::tr("Font %1 is broken, no embedding").arg(Datei));
103
        }
104
        else
105
        {
106
                FT_Stream fts = face->stream;
107
                bb.resize(fts->size);
108
                error = FT_Stream_Seek(fts, 0L);
109
                if (!error)
110
                        error = FT_Stream_Read(fts, reinterpret_cast<FT_Byte *>(bb.data()), fts->size);
111
                if (error)
112
                {
113
                        qDebug(QObject::tr("Font %1 is broken (read stream), no embedding").arg(Datei));
114
                        bb.resize(0);
115
                }
116
                /*
117
                if (showFontInformation)
118
                {
119
                        QFile f(Datei);
120
                        qDebug(QObject::tr("RawData for Font %1(%2): size=%3 filesize=%4").arg(Datei).arg(faceIndex).arg(bb.size()).arg(f.size()));
121
                }
122
                */
123
        }
124
        FT_Done_Face(face);
125
        FT_Done_FreeType(library);
126
}
127
 
128
 
68 Franz 129
/*
130
void Foi::FontBez()
131
{
132
        FT_Face face;
133
        FT_Library library;
134
        QString ts;
135
        QPixmap pm(200, 100);
136
        bool error;
137
        int  pen_x;
138
        int YPos = qApp->font().pointSize();
139
        uint n;
140
        error = FT_Init_FreeType( &library );
141
        error = FT_New_Face( library, Datei, 0, &face );
142
        ts = QString(face->family_name) + " " + QString(face->style_name);
143
        pm.fill();
144
        pen_x = 0;
145
        for (n = 0; n < ts.length(); n++)
146
                {
147
                uint dv = ts[n].unicode();
148
                error = FT_Set_Char_Size(       face, 0, qApp->font().pointSize()*64, 72, 72 );
149
                FT_Load_Char(face, dv, FT_LOAD_RENDER | FT_LOAD_NO_BITMAP | FT_LOAD_MONOCHROME);
150
                QByteArray bd(face->glyph->bitmap.rows * face->glyph->bitmap.pitch);
151
                uint yy = 0;
152
                uint adv;
153
                if ((face->glyph->bitmap.width % 8) == 0)
154
                        adv = face->glyph->bitmap.width / 8;
155
                else
156
                        adv = face->glyph->bitmap.width / 8 + 1;
157
                for (int y = 0; y < face->glyph->bitmap.rows; ++y)
158
                        {
159
                        memcpy(bd.data()+yy, face->glyph->bitmap.buffer+(y * face->glyph->bitmap.pitch), adv);
160
                        yy += adv;
161
                        }
162
                QBitmap bb(face->glyph->bitmap.width, face->glyph->bitmap.rows, (uchar*)bd.data(), false);
163
                QPixmap pixm(face->glyph->bitmap.width, face->glyph->bitmap.rows);
164
                if (!pixm.isNull())
165
                        {
166
                        pixm.fill(Qt::black);
167
                        pixm.setMask(bb);
168
                        QPainter p;
169
                        p.begin(&pm);
170
                        p.drawPixmap(pen_x+face->glyph->bitmap_left, YPos-face->glyph->bitmap_top, pixm);
171
                        p.end();
172
                        }
173
                pen_x += face->glyph->advance.x >> 6;
174
                }
175
        int high = qApp->fontMetrics().height();
176
        QPixmap pm2(pen_x, high);
177
        bitBlt(&pm2, 0, 0, &pm, 0, 0, pen_x, high);
178
        Appearance = pm2;
179
        FT_Done_FreeType( library );
180
        return;
181
}    */
3 paul 182
 
183
/*
184
        Class Foi_postscript
185
        Subclass of Foi, for Postscript fonts that could possibly have a .afm file
186
        associated with them for metrics information.
187
*/
188
 
189
class Foi_postscript : public Foi
190
{
191
        public:
68 Franz 192
                Foi_postscript(QString scname, QString path, bool embedps) :
193
                Foi(scname,path,embedps), metricsread(false)
3 paul 194
                {
195
                        HasMetrics=false;
196
                        HasKern = false;
197
                        Ascent = "0";
198
                        CapHeight = "0";
199
                        Descender = "0";
200
                        ItalicAngle = "0";
201
                        StdVW = "1";
202
                        FontBBox = "0 0 0 0";
203
                        IsFixedPitch = false;
2295 cbradney 204
                        typeCode = TYPE1;
3 paul 205
                        HasMetrics=true;
206
                }
207
 
208
                virtual QString RealName()
209
                {
210
                        return(cached_RealName);
211
                }
212
 
213
                virtual bool ReadMetrics()  // routine by Franz Schmid - modified by Alastair M. Robinson
214
                {
215
                        if(metricsread)
216
                                return(HasMetrics);
217
                        CharWidth.clear();
68 Franz 218
                        GlyphArray.clear();
84 Franz 219
                        QString tmp, tmp2, tmp3, tmp4;
80 Franz 220
                        double x, y;
68 Franz 221
                        FPointArray outlines;
222
                        struct GlyphR GRec;
3 paul 223
                        bool                    error;
224
                        FT_Library library;
225
                        FT_ULong  charcode;
226
                        FT_UInt   gindex;
227
                        FT_Face   face;
2171 fschmid 228
                        char *buf[50];
229
                        QString glyName = "";
220 Franz 230
                        isStroked = false;
3 paul 231
                        error = FT_Init_FreeType( &library );
232
                        if (error)
391 Franz 233
                        {
3 paul 234
                                UseFont = false;
2295 cbradney 235
                                qDebug(QObject::tr("Font %1 is broken (FreeType2), discarding it").arg(Datei));
3 paul 236
                                return false;
391 Franz 237
                        }
2295 cbradney 238
                        error = FT_New_Face( library, Datei, faceIndex, &face );
3 paul 239
                        if (error)
391 Franz 240
                        {
3 paul 241
                                UseFont = false;
2295 cbradney 242
                                qDebug(QObject::tr("Font %1 is broken (no Face), discarding it").arg(Datei));
243
                                FT_Done_FreeType( library );
3 paul 244
                                return false;
391 Franz 245
                        }
80 Franz 246
                        uniEM = static_cast<double>(face->units_per_EM);
3 paul 247
                        QString afnm = Datei.left(Datei.length()-3);
248
                        QFile afm(afnm+"afm");
249
                        if(!(afm.exists()))
391 Franz 250
                        {
3 paul 251
                                afm.setName(afnm+"Afm");
252
                                if(!(afm.exists()))
253
                                        afm.setName(afnm+"AFM");
391 Franz 254
                        }
3 paul 255
                        if (afm.exists())
256
                                error = FT_Attach_File(face, afm.name());
257
                        HasKern = FT_HAS_KERNING(face);
2163 fschmid 258
                        HasNames = FT_HAS_GLYPH_NAMES(face);
3 paul 259
                        Ascent = tmp.setNum(face->ascender);
260
                        Descender = tmp.setNum(face->descender);
68 Franz 261
                        numDescender = face->descender / uniEM;
262
                        numAscent = face->ascender / uniEM;
263
                        underline_pos = face->underline_position / uniEM;
264
                        strikeout_pos = numAscent / 3;
265
                        strokeWidth = face->underline_thickness / uniEM;
3 paul 266
                        CapHeight = Ascent;
267
                        ItalicAngle = "0";
268
                        StdVW = "1";
84 Franz 269
                        FontBBox = tmp.setNum(face->bbox.xMin)+" "+tmp2.setNum(face->bbox.yMin)+" "+tmp3.setNum(face->bbox.xMax)+" "+tmp4.setNum(face->bbox.yMax);
3 paul 270
                        IsFixedPitch = face->face_flags & 4;
896 fschmid 271
                        setBestEncoding(face);
3 paul 272
                        gindex = 0;
273
                        charcode = FT_Get_First_Char( face, &gindex );
2295 cbradney 274
                        int goodGlyph = 0;
275
                        int invalidGlyph = 0;
3 paul 276
                        while ( gindex != 0 )
391 Franz 277
                        {
220 Franz 278
                                error = FT_Load_Glyph( face, gindex, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP );
279
                                if (error)
391 Franz 280
                                {
2295 cbradney 281
                                        ++invalidGlyph;
282
                                        qDebug(QObject::tr("Font %1 has broken glyph %2 (charcode %3)").arg(Datei).arg(gindex).arg(charcode));
2394 cbradney 283
                                        charcode = FT_Get_Next_Char( face, charcode, &gindex );
284
                                        continue;
391 Franz 285
                                }
2295 cbradney 286
                                ++goodGlyph;
220 Franz 287
                                double ww = face->glyph->metrics.horiAdvance / uniEM;
288
                                if (face->glyph->format == FT_GLYPH_FORMAT_PLOTTER)
289
                                        isStroked = true;
290
                                error = false;
291
                                outlines = traceChar(face, charcode, 10, &x, &y, &error);
292
                                if (!error)
391 Franz 293
                                {
220 Franz 294
                                        CharWidth.insert(charcode, ww);
295
                                        GRec.Outlines = outlines.copy();
296
                                        GRec.x = x;
297
                                        GRec.y = y;
298
                                        GlyphArray.insert(charcode, GRec);
391 Franz 299
                                }
2171 fschmid 300
/* The following lines are a check for some weired fonts which have invalid "post" tables */
301
                                FT_Get_Glyph_Name(face, gindex, buf, 50);
302
                                QString newName = QString(reinterpret_cast<char*>(buf));
303
                                if (newName == glyName)
304
                                        HasNames = false;
305
                                glyName = newName;
3 paul 306
                                charcode = FT_Get_Next_Char( face, charcode, &gindex );
391 Franz 307
                        }
2295 cbradney 308
                        FT_Done_Face( face );
3 paul 309
                        FT_Done_FreeType( library );
2394 cbradney 310
                        if (invalidGlyph > 0) {
311
                                UseFont = false;
312
                                qDebug(QObject::tr("Font %1 is broken and will be discarded").arg(Datei));
313
                        }                              
220 Franz 314
                        HasMetrics=UseFont;
315
                        metricsread=UseFont;
3 paul 316
                        return(HasMetrics);
317
                }
318
        private:
319
                bool metricsread;
320
};
321
 
322
/*
323
        Class Foi_pfb
324
        Subclass of Foi, specifically for Adobe type 1 .pfb fonts.
325
        Implements: RealName() and EmbedFont().
326
*/
327
 
328
class Foi_pfb : public Foi_postscript
329
{
330
        public:
68 Franz 331
                Foi_pfb(QString scname, QString path, bool embedps) :
332
                Foi_postscript(scname,path,embedps)
3 paul 333
                {
2295 cbradney 334
                        formatCode = PFB;
3 paul 335
                }
336
 
337
                virtual bool EmbedFont(QString &str)
338
                {
2295 cbradney 339
                        QByteArray bb;
340
                        RawData(bb);
3 paul 341
                        QString tmp2 = "";
2295 cbradney 342
                        if ((bb.size() > 2) &&  (bb[0] == char(0x80)) && (static_cast<int>(bb[1]) == 1))
3 paul 343
                        {
2295 cbradney 344
                                QString tmp3="";
345
                                QString tmp4 = "";
346
                                uint posi,cxxc=0;
347
                                for (posi = 6; posi < bb.size(); ++posi)
3 paul 348
                                {
2295 cbradney 349
                                        if ((bb[posi] == char(0x80)) && (posi+1 < bb.size()) && (static_cast<int>(bb[posi+1]) == 2))
350
                                                break;
351
                                        str += bb[posi];
352
                                }
353
                                uint ulen;
354
                                if (posi+6 < bb.size())
355
                                {
3 paul 356
                                        ulen = bb[posi+2] & 0xff;
357
                                        ulen |= (bb[posi+3] << 8) & 0xff00;
358
                                        ulen |= (bb[posi+4] << 16) & 0xff0000;
359
                                        ulen |= (bb[posi+5] << 24) & 0xff000000;
360
                                        posi += 6;
2295 cbradney 361
                                        if (posi + ulen > bb.size())
362
                                                ulen = bb.size() - posi - 1;
3 paul 363
                                        char linebuf[80];
364
                                        cxxc=0;
365
                                        for (uint j = 0; j < ulen; ++j)
366
                                        {
367
                                                unsigned char u=bb[posi];
368
                                                linebuf[cxxc]=((u >> 4) & 15) + '0';
369
                                                if(u>0x9f) linebuf[cxxc]+='a'-':';
370
                                                ++cxxc;
371
                                                u&=15; linebuf[cxxc]=u + '0';
372
                                                if(u>0x9) linebuf[cxxc]+='a'-':';
373
                                                ++posi;
374
                                                ++cxxc;
375
                                                if (cxxc > 72)
376
                                                {
377
                                                        linebuf[cxxc++]='\n';
378
                                                        linebuf[cxxc++]=0;
379
                                                        str += linebuf;
380
                                                        cxxc = 0;
381
                                                }
382
                                        }
383
                                        linebuf[cxxc]=0;
384
                                        str += linebuf;
385
                                        str += "\n";
386
                                }
2295 cbradney 387
                                posi += 6;
388
                                for (uint j = posi; j < bb.size(); ++j)
389
                                {
390
                                        if ((bb[j] == static_cast<char>(0x80)) && (j+1 < bb.size()) && (static_cast<int>(bb[j+1]) == 3))
391
                                                break;
392
                                        if(bb[j]=='\r')
393
                                                str+="\n";
394
                                        else
395
                                                str += bb[j];
396
                                }
397
                                str += "\n";
398
                                cxxc = 0;
399
                                return true;
3 paul 400
                        }
2295 cbradney 401
                        else
402
                        {
403
                                qDebug(QObject::tr("Font %1 cannot be read, no embedding").arg(Datei));
404
                                return false;
405
                        }
3 paul 406
                }
407
};
408
 
409
/*
410
        Class Foi_pfa
411
        Subclass of Foi, specifically for Adobe type 1 and type 3 .pfa fonts.
412
        Implements: RealName() and EmbedFont().
413
*/
414
 
415
class Foi_pfa : public Foi_postscript
416
{
417
        public:
68 Franz 418
                Foi_pfa(QString scname, QString path, bool embedps) :
419
                Foi_postscript(scname,path,embedps)
3 paul 420
                {
2295 cbradney 421
                        formatCode = PFA;
3 paul 422
                }
423
                virtual bool EmbedFont(QString &str)
424
                {
2295 cbradney 425
                        QByteArray bb;
426
                        RawData(bb);
427
                        if (bb.size() > 2 && bb[0] == '%' && bb[1] == '!')
428
                        {
429
                                // this is ok since bb will not contain '\0'
430
                                str.append(bb);
431
                                return true;
432
                        }
433
                        return false;
3 paul 434
                }
435
};
436
 
437
 
2295 cbradney 438
 
3 paul 439
/***************************************************************************/
440
 
441
SCFonts::~SCFonts()
442
{
443
}
444
 
2508 fschmid 445
void SCFonts::updateFontMap()
446
{
447
        fontMap.clear();
448
        SCFontsIterator it( *this );
449
        for ( ; it.current(); ++it)
450
        {
451
                if (it.current()->UseFont)
452
                {
453
                        if (fontMap.contains(it.current()->Family))
454
                        {
455
                                QStringList effect;
456
                                if (!fontMap[it.current()->Family].contains(it.current()->Effect))
457
                                {
458
                                        fontMap[it.current()->Family].append(it.current()->Effect);
459
                                }
460
                        }
461
                        else
462
                        {
463
                                QStringList effect;
464
                                effect.append(it.current()->Effect);
465
                                fontMap.insert(it.current()->Family, effect);
466
                        }
467
                }
468
        }
469
}
470
 
3 paul 471
/* Add a path to the list of fontpaths, ensuring that
472
   a trailing slash is present.
473
   Checks to make sure this path is not already present
474
   before adding.
475
*/
476
void SCFonts::AddPath(QString p)
477
{
478
        if(p.right(1) != "/")
479
          p += "/";
480
        if(FontPath.find(p)==-1)
481
                FontPath.insert(FontPath.count(),p);
482
}
483
 
494 fschmid 484
void SCFonts::AddScalableFonts(const QString &path, QString DocName)
3 paul 485
{
494 fschmid 486
        FT_Library library = NULL;
487
        QString pathfile;
68 Franz 488
        bool error;
84 Franz 489
        error = FT_Init_FreeType( &library );        
490
        QDir d(path, "*", QDir::Name, QDir::Dirs | QDir::Files | QDir::Readable);
68 Franz 491
        if ((d.exists()) && (d.count() != 0))
494 fschmid 492
        {
493
                for (uint dc = 0; dc < d.count(); ++dc)
3 paul 494
                {
84 Franz 495
                        QFileInfo fi(path+d[dc]);
496
                        if (!fi.exists())      // Sanity check for broken Symlinks
497
                                continue;
2295 cbradney 498
 
499
                        qApp->processEvents();
500
 
84 Franz 501
                        if (fi.isSymLink())
494 fschmid 502
                        {
84 Franz 503
                                QFileInfo fi3(fi.readLink());
504
                                if (fi3.isRelative())
505
                                        pathfile = path+fi.readLink();
506
                                else
507
                                        pathfile = fi3.absFilePath();
494 fschmid 508
                        }
84 Franz 509
                        else
510
                                pathfile = path+d[dc];
511
                        QFileInfo fi2(pathfile);
2295 cbradney 512
                        if (fi2.isDir())
513
                        {
514
                                if (DocName == "")
515
                                        AddScalableFonts(pathfile);
516
                                continue;
517
                        }
504 cbradney 518
                        QString ext = fi.extension(false).lower();
519
                        QString ext2 = fi2.extension(false).lower();
520
                        if ((ext != ext2) && (ext == "")) ext = ext2;
2295 cbradney 521
                        if ((ext == "ttc") || (ext == "dfont") || (ext == "pfa") || (ext == "pfb") || (ext == "ttf") || (ext == "otf"))
414 Franz 522
                        {
2295 cbradney 523
                                error = AddScalableFont(pathfile, library, DocName);
72 Franz 524
                                if (error)
494 fschmid 525
                                        qDebug(QObject::tr("Font %1 is broken, discarding it").arg(pathfile));
414 Franz 526
                        }
2295 cbradney 527
#ifdef FT_MACINTOSH
528
                        else if (ext == "" && DocName == "")
529
                        {
530
                                error = AddScalableFont(pathfile, library, DocName);
531
                                if (error)
532
                                        error = AddScalableFont(pathfile + "/rsrc",library, DocName);
533
                                if (error)
534
                                        qDebug(QObject::tr("Font %1 is broken, discarding it").arg(pathfile));
535
                        }
536
#endif                          
3 paul 537
                }
494 fschmid 538
        }
68 Franz 539
        FT_Done_FreeType( library );
3 paul 540
}
541
 
2295 cbradney 542
/**
543
 * tests magic words to determine the fontformat and preliminary fonttype
544
 */
545
void getFontFormat(FT_Face face, Foi::FontFormat & fmt, Foi::FontType & type)
494 fschmid 546
{
2295 cbradney 547
        static const char* T42_HEAD      = "%!PS-TrueTypeFont";
548
        static const char* T1_HEAD      = "%!FontType1";
549
        static const char* T1_ADOBE_HEAD = "%!PS-AdobeFont-1";
550
        static const char* PSFONT_ADOBE2_HEAD  = "%!PS-Adobe-2.0 Font";
551
        static const char* PSFONT_ADOBE21_HEAD  = "%!PS-Adobe-2.1 Font";
552
        static const char* PSFONT_ADOBE3_HEAD  = "%!PS-Adobe-3.0 Resource-Font";
2730 cbradney 553
        static const int   FONT_NO_ERROR = 0;
2295 cbradney 554
 
555
        const FT_Stream fts = face->stream;
556
        char buf[128];
557
 
558
        fmt = Foi::UNKNOWN_FORMAT;
559
        type = Foi::UNKNOWN_TYPE;
2730 cbradney 560
        if (FT_Stream_Seek(fts, 0L) == FONT_NO_ERROR && FT_Stream_Read(fts, reinterpret_cast<FT_Byte *>(buf), 128) == FONT_NO_ERROR)
494 fschmid 561
        {
2295 cbradney 562
                if(strncmp(buf,T42_HEAD,strlen(T42_HEAD)) == 0)
1321 fschmid 563
                {
2295 cbradney 564
                        fmt = Foi::TYPE42;
565
                        type = Foi::TTF;
1321 fschmid 566
                }
2295 cbradney 567
                else if(strncmp(buf,T1_HEAD,strlen(T1_HEAD)) == 0 ||
568
                            strncmp(buf,T1_ADOBE_HEAD,strlen(T1_ADOBE_HEAD)) == 0)
1321 fschmid 569
                {
2295 cbradney 570
                        fmt = Foi::PFA;
571
                        type = Foi::TYPE1;
1321 fschmid 572
                }
2295 cbradney 573
                else if(strncmp(buf,PSFONT_ADOBE2_HEAD,strlen(PSFONT_ADOBE2_HEAD)) == 0 ||
574
                            strncmp(buf,PSFONT_ADOBE21_HEAD,strlen(PSFONT_ADOBE21_HEAD)) == 0 ||
575
                            strncmp(buf,PSFONT_ADOBE3_HEAD,strlen(PSFONT_ADOBE3_HEAD)) ==0)
1321 fschmid 576
                {
2295 cbradney 577
                        // Type2(CFF), Type0(Composite/CID), Type 3, Type 14 etc would end here
578
                        fmt = Foi::PFA;
579
                        type = Foi::UNKNOWN_TYPE;
1321 fschmid 580
                }
2295 cbradney 581
                else if(buf[0] == '\200' && buf[1] == '\1')
1321 fschmid 582
                {
2295 cbradney 583
                        fmt = Foi::PFB;
584
                        type = Foi::TYPE1;
1321 fschmid 585
                }
2295 cbradney 586
                else if(buf[0] == '\0' && buf[1] == '\1'
587
                                && buf[2] == '\0' && buf[3] == '\0')
494 fschmid 588
                {
2295 cbradney 589
                        fmt = Foi::SFNT;
590
                        type = Foi::TTF;
591
                }
592
                else if(strncmp(buf,"true",4) == 0)
593
                {
594
                        fmt = Foi::SFNT;
595
                        type = Foi::TTF;
596
                }
597
                else if(strncmp(buf,"ttcf",4) == 0)
598
                {
599
                        fmt = Foi::TTCF;
600
                        type = Foi::OTF;
601
                }
602
                else if(strncmp(buf,"OTTO",4) == 0)
603
                {
604
                        fmt = Foi::SFNT;
605
                        type = Foi::OTF;
606
                }
607
                // missing: raw CFF
608
        }
609
}
610
 
611
/**
612
 * Checks face, which must be sfnt based, for the subtype.
613
 * Possible values: TTF, CFF, OTF
614
 */
615
void getSFontType(FT_Face face, Foi::FontType & type)
616
{
617
        if (FT_IS_SFNT(face))
618
        {
619
                FT_ULong ret = 0;
620
                bool hasGlyph = ! FT_Load_Sfnt_Table(face, TTAG_glyf, 0, NULL,  &ret);
621
                hasGlyph &= ret > 0;
622
                bool hasCFF = ! FT_Load_Sfnt_Table(face, TTAG_CFF, 0, NULL,  &ret);
623
                hasCFF &= ret > 0;
624
                if (hasGlyph)
625
                        type = Foi::TTF;
626
                else if (hasCFF)
627
                        type = Foi::OTF;
628
                // TODO: CID or no
629
        }
630
}
631
 
632
// Load a single font into the library from the passed filename. Returns true on error.
633
bool SCFonts::AddScalableFont(QString filename, FT_Library &library, QString DocName)
634
{
635
        Foi::FontFormat format;
636
        Foi::FontType   type;
637
        FT_Face         face = NULL;
638
 
639
        bool error = FT_New_Face( library, filename, 0, &face );
640
        if (error)
641
        {
642
                if (face != NULL)
643
                        FT_Done_Face( face );
644
                return true;
645
        }
646
 
647
        getFontFormat(face, format, type);
648
 
649
        if (format == Foi::UNKNOWN_FORMAT)
650
        {
651
                qDebug(QObject::tr("Failed to load font %1 - font type unknown").arg(filename));
652
                error = true;
653
        }
654
 
655
        int faceindex=0;
656
 
657
        while (!error)
658
        {
659
                QString ts = QString(face->family_name) + " " + QString(face->style_name);
660
                Foi *t = find(ts);
661
                if (!t)
662
                {
663
                        switch (format)
664
                        {
665
                                case Foi::PFA:
666
                                        t = new Foi_pfa(ts, filename, true);
667
                                        break;
2508 fschmid 668
                                case Foi::PFB:
2295 cbradney 669
                                        t = new Foi_pfb(ts, filename, true);
670
                                        break;
671
                                case Foi::SFNT:
672
                                        t = new Foi_ttf(ts, filename, true);
673
                                        getSFontType(face, t->typeCode);
674
                                        if (t->typeCode == Foi::OTF)
675
                                        {
676
                                                t->isOTF = true;
677
                                                t->Subset = true;
678
                                        }
679
                                        break;
680
                                case Foi::TTCF:
681
                                        t = new Foi_ttf(ts, filename, true);
682
                                        t->formatCode = Foi::TTCF;
683
                                        t->typeCode = Foi::TTF;
684
                                        //getSFontType(face, t->typeCode);
685
                                        if (t->typeCode == Foi::OTF)
686
                                        {
687
                                                t->isOTF = true;
688
                                                t->Subset = true;
689
                                        }
690
                                        break;
691
                                case Foi::TYPE42:
692
                                        t = new Foi_ttf(ts, filename, true);
693
                                        getSFontType(face, t->typeCode);
694
                                        if (t->typeCode == Foi::OTF)
695
                                        {
696
                                                t->isOTF = true;
697
                                                t->Subset = true;
698
                                        }
699
                                        break;
700
                        }
701
                        const char* psName = FT_Get_Postscript_Name(face);
702
                        if (psName)
703
                                t->cached_RealName = QString(psName);
704
                        else
705
                                t->cached_RealName = ts;
494 fschmid 706
                        t->Font = qApp->font();
707
                        t->Font.setPointSize(qApp->font().pointSize());
708
                        insert(ts,t);
709
                        t->EmbedPS = true;
710
                        t->UseFont = true;
711
                        t->CharWidth[13] = 0;
712
                        t->CharWidth[28] = 0;
713
                        t->CharWidth[9] = 1;
714
                        t->Family = QString(face->family_name);
759 cbradney 715
                        t->Effect = QString(face->style_name);
2295 cbradney 716
                        t->faceIndex = faceindex;
494 fschmid 717
                        t->PrivateFont = DocName;
2633 cbradney 718
                        //setBestEncoding(face); //AV
2295 cbradney 719
                        switch (face->charmap? face->charmap->encoding : -1)
720
                        {
721
                                case     FT_ENCODING_ADOBE_STANDARD:
722
                                        t->FontEnc = QString("StandardEncoding");
723
                                        break;
724
                                case     FT_ENCODING_APPLE_ROMAN:
725
                                        t->FontEnc = QString("MacRomanEncoding");
726
                                        break;
727
                                case     FT_ENCODING_ADOBE_EXPERT:
728
                                        t->FontEnc = QString("MacExpertEncoding");
729
                                        break;
730
                                case     FT_ENCODING_ADOBE_LATIN_1:
731
                                        t->FontEnc = QString("WinAnsiEncoding");
732
                                        break;
733
                                case     FT_ENCODING_UNICODE:
734
                                        t->FontEnc = QString("Unicode");
735
                                        break;
736
                                default:
737
                                        t->FontEnc = QString();
738
                        }
739
                        if (showFontInformation)
740
                                qDebug(QObject::tr("Font %1 loaded from %2(%3)").arg(t->cached_RealName).arg(filename).arg(faceindex+1));
741
 
742
/*
743
//debug
744
                        QByteArray bb;
745
                        t->RawData(bb);
746
                        QFile dump(QString("/tmp/fonts/%1-%2").arg(ts).arg(psName));
747
                        dump.open(IO_WriteOnly);
748
                        QDataStream os(&dump);
749
                        os.writeRawBytes(bb.data(), bb.size());
750
                        dump.close();
751
*/
752
                        FT_Done_Face(face);
2542 cbradney 753
                        face=NULL;
2295 cbradney 754
                        ++faceindex;
755
                        error = FT_New_Face( library, filename, faceindex, &face );
494 fschmid 756
                }
2295 cbradney 757
                else
758
                {
759
                        if (showFontInformation)
760
                                qDebug(QObject::tr("Font %1(%2) is duplicate of %3").arg(filename).arg(faceindex+1).arg(t->fontPath()));
761
                        // this is needed since eg. AppleSymbols will happily return a face for *any* face_index
762
                        error = true;
763
                }
764
        } //while
765
 
494 fschmid 766
        if (face != 0)
767
                FT_Done_Face( face );
768
        return false;
769
}
770
 
771
void SCFonts::removeFont(QString name)
772
{
773
        remove(name);
2508 fschmid 774
        updateFontMap();
494 fschmid 775
}
776
 
776 fschmid 777
#ifdef HAVE_FONTCONFIG
778
// Use Fontconfig to locate and load fonts.
779
void SCFonts::AddFontconfigFonts()
780
{
2295 cbradney 781
        // All-in-one library setup. Perhaps this should be in
782
        // the SCFonts constructor.
783
        FcConfig* FcInitLoadConfigAndFonts();
784
        // The pattern controls what fonts to match. In this case we want to
785
        // match all scalable fonts, but ignore bitmap fonts.
786
        FcPattern* pat = FcPatternBuild(NULL,
787
                                                                        FC_SCALABLE, FcTypeBool, true,
788
                                                                        NULL);
789
        // The ObjectSet tells FontConfig what information about each match to return.
790
        // We currently just need FC_FILE, but other info like font family and style
791
        // is availible - see "man fontconfig".
792
        FcObjectSet* os = FcObjectSetBuild (FC_FILE, (char *) 0);
793
        // Now ask fontconfig to retrieve info as specified in 'os' about fonts
794
        // matching pattern 'pat'.
795
        FcFontSet* fs = FcFontList(0, pat, os);
796
        FcObjectSetDestroy(os);
797
        FcPatternDestroy(pat);
798
        // Create the Freetype library
799
        bool error;
800
        FT_Library library = NULL;
801
        error = FT_Init_FreeType( &library );
802
        // Now iterate over the font files and load them
803
        int i;
804
        for (i = 0; i < fs->nfont; i++)
805
        {
806
                FcChar8 *file = NULL;
807
                if (FcPatternGetString (fs->fonts[i], FC_FILE, 0, &file) == FcResultMatch)
808
                {
809
                        if (showFontInformation)
810
                                qDebug(QObject::tr("Loading font %1 (found using fontconfig)").arg(QString((char*)file)));
811
                        error = AddScalableFont(QString((char*)file), library, "");
812
                        if (error)
813
                                qDebug(QObject::tr("Font %1 (found using fontconfig) is broken, discarding it").arg(QString((char*)file)));
814
                }
815
                else
816
                        if (showFontInformation)
817
                                qDebug(QObject::tr("Failed to load a font - freetype2 couldn't find the font file"));
818
        }
819
        FT_Done_FreeType( library );
776 fschmid 820
}
821
 
822
#else
2295 cbradney 823
#ifndef QT_MAC
776 fschmid 824
 
3 paul 825
void SCFonts::AddXFontPath()
826
{
827
        int pathcount,i;
828
        Display *display=XOpenDisplay(NULL);
829
        char **fontpath=XGetFontPath(display,&pathcount);
830
        for(i=0; i<pathcount; ++i)
831
                AddPath(fontpath[i]);
832
        XFreeFontPath(fontpath);
833
}
834
 
835
/* replacement for AddXFontServerPath() for correctly parsing
836
 * RedHad-Style /etc/X11/fs/config files */
837
 
838
void SCFonts::AddXFontServerPath()
839
{
840
        QFile fs("/etc/X11/fs/config");
841
        if(!(fs.exists()))
842
        {
843
                fs.setName("/usr/X11R6/lib/X11/fs/config");
844
                if(!(fs.exists()))
845
                {
846
                        fs.setName("/usr/X11/lib/X11/fs/config");
847
                        if(!(fs.exists()))
848
                                return;
849
                }
850
        }
851
 
852
        if (fs.open(IO_ReadOnly))
853
        {
854
                QString fsconfig,paths,tmp;
855
                QTextStream tsx(&fs);
856
                fsconfig = tsx.read();
857
                fs.close();
858
 
859
                int pos = fsconfig.find("catalogue");
860
                paths = fsconfig.mid(pos);
861
                paths = paths.mid(paths.find("=")+1);
862
 
863
                pos=0;
864
                do {
865
                        pos = paths.find("\n",pos+1);
866
                } while (pos > -1 && paths.mid(pos-1, 1) == ",");
867
 
868
                if(pos<0) pos=paths.length();
869
                paths = paths.left(pos);
870
                paths = paths.simplifyWhiteSpace();
871
                paths.replace(QRegExp(" "), "");
872
                paths.replace(QRegExp(","), "\n");
873
                paths += "\n";
874
                paths = paths.stripWhiteSpace();
875
 
876
                pos=-1;
877
                do {
878
                        int pos2;
879
                        pos2 = paths.find("\n",pos+1);
880
                        tmp = paths.mid(pos+1,(pos2-pos)-1);
881
                        pos=pos2;
882
 
883
                        AddPath(tmp);
884
 
885
                } while (pos > -1);
886
        }
887
}
776 fschmid 888
#endif
2295 cbradney 889
#endif
3 paul 890
 
2510 craig 891
/* Add an extra path to our font search path,
892
 * allowing a user to have extra fonts installed
893
 * only for this user. Can also be used also as an emergency
894
 * fallback if no suitable fonts are found elsewere */
3 paul 895
void SCFonts::AddUserPath(QString pf)
896
{
2510 craig 897
        PrefsContext *pc = prefsFile->getContext("Fonts");
898
        PrefsTable *extraDirs = pc->getTable("ExtraFontDirs");
899
        for (int i = 0; i < extraDirs->getRowCount(); ++i)
900
                AddPath(extraDirs->get(i, 0));
3 paul 901
}
902
 
2295 cbradney 903
void SCFonts::GetFonts(QString pf, bool showFontInfo)
3 paul 904
{
2295 cbradney 905
        showFontInformation=showFontInfo;
3 paul 906
        FontPath.clear();
907
        AddUserPath(pf);
2295 cbradney 908
// if fontconfig is there, it does all the work
909
#if HAVE_FONTCONFIG
776 fschmid 910
        for(QStrListIterator fpi(FontPath) ; fpi.current() ; ++fpi)
911
                AddScalableFonts(fpi.current());
912
        AddFontconfigFonts();
913
#else
2295 cbradney 914
// if FreeType thinks we are on Mac, let it search the default paths
915
#if FT_MACINTOSH
916
        AddScalableFonts(QDir::homeDirPath() + "/Library/Fonts/");
917
        AddScalableFonts("/Library/Fonts/");
918
        AddScalableFonts("/Network/Library/Fonts/");
919
        AddScalableFonts("/System/Library/Fonts/");
920
#endif
921
// on X11 look there:
922
#ifdef Q_WS_X11
3 paul 923
        AddXFontPath();
924
        AddXFontServerPath();
2295 cbradney 925
#endif
926
// add user and X11 fonts:
927
        for(QStrListIterator fpi(FontPath) ; fpi.current() ; ++fpi)
3 paul 928
                AddScalableFonts(fpi.current());
494 fschmid 929
#endif
2508 fschmid 930
        updateFontMap();
494 fschmid 931
}