~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kcontrol/kfontinst/strigi-analyzer/FontEngine.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * KFontInst - KDE Font Installer
 
3
 *
 
4
 * Copyright 2003-2007 Craig Drummond <craig@kde.org>
 
5
 *
 
6
 * ----
 
7
 *
 
8
 * This program is free software; you can redistribute it and/or modify
 
9
 * it under the terms of the GNU General Public License as published by
 
10
 * the Free Software Foundation; either version 2 of the License, or
 
11
 * (at your option) any later version.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License
 
19
 * along with this program; see the file COPYING.  If not, write to
 
20
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
 * Boston, MA 02110-1301, USA.
 
22
 */
 
23
 
 
24
//
 
25
// This class contains code inspired/copied/nicked from mkfontscale. Specifically
 
26
// the getName(), lookupName(), and the getFoundry() routines...
 
27
//
 
28
// mkfontscale's (C) notice is:
 
29
/*
 
30
  Copyright (c) 2002 by Juliusz Chroboczek
 
31
 
 
32
  Permission is hereby granted, free of charge, to any person obtaining a copy
 
33
  of this software and associated documentation files (the "Software"), to deal
 
34
  in the Software without restriction, including without limitation the rights
 
35
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
36
  copies of the Software, and to permit persons to whom the Software is
 
37
  furnished to do so, subject to the following conditions:
 
38
 
 
39
  The above copyright notice and this permission notice shall be included in
 
40
  all copies or substantial portions of the Software.
 
41
 
 
42
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
43
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
44
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 
45
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
46
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
47
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
48
  THE SOFTWARE.
 
49
*/
 
50
 
 
51
#include "FontEngine.h"
 
52
#include "Misc.h"
 
53
#include "Fc.h"
 
54
#include <KDE/KGlobal>
 
55
#include <kascii.h>
 
56
#include <ctype.h>
 
57
#include <string.h>
 
58
#include <stdlib.h>
 
59
#include <stdio.h>
 
60
#include <iostream>
 
61
#include <sys/types.h>
 
62
#include <sys/stat.h>
 
63
#include <fcntl.h>
 
64
#include <ft2build.h>
 
65
#include FT_SFNT_NAMES_H
 
66
#include FT_TRUETYPE_IDS_H
 
67
#include FT_TRUETYPE_TABLES_H
 
68
#include FT_TYPE1_TABLES_H
 
69
#include <QtCore/QBuffer>
 
70
#include <QtCore/QTextStream>
 
71
 
 
72
namespace KFI
 
73
{
 
74
 
 
75
static unsigned long ftStreamRead(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count)
 
76
{
 
77
    QByteArray *in((QByteArray *)stream->descriptor.pointer);
 
78
 
 
79
    if((offset+count)<=(unsigned long)in->size())
 
80
    {
 
81
        memcpy(buffer, &(in->data()[offset]), count);
 
82
        return count;
 
83
    }
 
84
 
 
85
    return 0;
 
86
}
 
87
 
 
88
static FT_Error openFtFace(FT_Library library, QByteArray &in, FT_Long index, FT_Face *face)
 
89
{
 
90
    FT_Open_Args args;
 
91
    FT_Stream    stream;
 
92
    FT_Error     error;
 
93
 
 
94
    if(NULL==(stream=(FT_Stream)calloc(1, sizeof(*stream))))
 
95
        return FT_Err_Out_Of_Memory;
 
96
 
 
97
    stream->descriptor.pointer = &in;
 
98
    stream->pathname.pointer   = NULL;
 
99
    stream->size               = in.size();
 
100
    stream->pos                = 0;
 
101
 
 
102
    stream->read  = ftStreamRead;
 
103
    args.flags  = FT_OPEN_STREAM;
 
104
    args.stream = stream;
 
105
 
 
106
    error = FT_Open_Face(library, &args, index, face);
 
107
 
 
108
    if (FT_Err_Ok!=error)
 
109
        free(stream);
 
110
    else
 
111
        (*face)->face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
 
112
 
 
113
    return error;
 
114
}
 
115
 
 
116
// TTF  : 00 01 00 00 00                         5
 
117
//      : FFIL                                   4
 
118
//      : <65>  FFIL                            69
 
119
// TTC  : ttcf                                   4
 
120
// OTF  : OTTO                                   4
 
121
// Type1: %!PS-AdobeFont-1.                     17
 
122
//      : ?? ?? ?? ?? ?? ?? %!PS-AdobeFont-1.   23
 
123
//      : %!FontType1-1.                        14
 
124
//      : ?? ?? ?? ?? ?? ?? %!FontType1-1.      20
 
125
//      : LWFN                                   4
 
126
//      : <65> LWFN                             69
 
127
// AFM  : StartFontMetrics                      16
 
128
// BDF  : STARTFONT 20                          10
 
129
// PCF  : 01 fcp                                 4
 
130
static const int constHeaderLen=69;
 
131
 
 
132
CFontEngine::EType CFontEngine::getType(const char *fileName)
 
133
{
 
134
    EType type(TYPE_UNKNOWN);
 
135
    int   fd=::open(fileName, O_RDONLY);
 
136
 
 
137
    if(-1!=fd)
 
138
    {
 
139
        unsigned char header[constHeaderLen];
 
140
 
 
141
        if(constHeaderLen==::read(fd, header, constHeaderLen))
 
142
            type=getType(fileName, header);
 
143
        ::close(fd);
 
144
    }
 
145
 
 
146
    return type;
 
147
}
 
148
 
 
149
CFontEngine::EType CFontEngine::getType(const char *fileName, Strigi::InputStream *in)
 
150
{
 
151
    Q_ASSERT( in );
 
152
 
 
153
    static const int constHeaderLen=69;
 
154
    const char * h;
 
155
    int          n=in->read(h, constHeaderLen, constHeaderLen);
 
156
 
 
157
    in->reset(0);
 
158
 
 
159
    return getType(fileName, n==constHeaderLen ? (const unsigned char *)h : NULL);
 
160
}
 
161
 
 
162
CFontEngine::EType CFontEngine::getType(const char *fileName, const unsigned char *header)
 
163
{
 
164
    if(header)
 
165
    {
 
166
        if( (0x00==header[0] && 0x01==header[1] && 0x00==header[2] && 0x00==header[3] && 0x00==header[4]) ||
 
167
            ('F'==header[0] && 'F'==header[1] && 'I'==header[2] && 'L'==header[3]) ||
 
168
            ('F'==header[65] && 'F'==header[66] && 'I'==header[67] && 'L'==header[68]))
 
169
            return TYPE_TTF;
 
170
 
 
171
        if('t'==header[0] && 't'==header[1] && 'c'==header[2] && 'f'==header[3])
 
172
            return TYPE_TTC;
 
173
 
 
174
        if('O'==header[0] && 'T'==header[1] && 'T'==header[2] && 'O'==header[3])
 
175
            return TYPE_OTF;
 
176
 
 
177
        if(0x01==header[0] && 'f'==header[1] && 'c'==header[2] && 'p'==header[3])
 
178
            return TYPE_PCF;
 
179
 
 
180
        if(0==memcmp(header, "STARTFONT", 9) && 0x20==header[9])
 
181
            return TYPE_BDF;
 
182
 
 
183
        if(0==memcmp(header, "%!PS-AdobeFont-1.", 17) ||
 
184
           0==memcmp(&header[6], "%!PS-AdobeFont-1.", 17) ||
 
185
           0==memcmp(header, "%!FontType1-1.", 14) ||
 
186
           0==memcmp(&header[6], "%!FontType1-1.", 14) ||
 
187
           ('L'==header[0] && 'W'==header[1] && 'F'==header[2] && 'N'==header[3]) ||
 
188
           ('L'==header[65] && 'W'==header[66] && 'F'==header[67] && 'N'==header[68]))
 
189
            return TYPE_TYPE1;
 
190
 
 
191
        if(0==memcmp(header, "StartFontMetrics", 16))
 
192
            return TYPE_AFM;
 
193
    }
 
194
 
 
195
    // Right mime 'magic' failed, try by extension...
 
196
    if(Misc::checkExt(fileName, "ttf"))
 
197
        return TYPE_TTF;
 
198
 
 
199
    if(Misc::checkExt(fileName, "ttc"))
 
200
        return TYPE_TTC;
 
201
 
 
202
    if(Misc::checkExt(fileName, "otf"))
 
203
        return TYPE_OTF;
 
204
 
 
205
    if(Misc::checkExt(fileName, "pfa") || Misc::checkExt(fileName, "pfb"))
 
206
        return TYPE_TYPE1;
 
207
 
 
208
    //
 
209
    // NOTE: Do not accept .gz extension - strigi will decompress for us.
 
210
    if(Misc::checkExt(fileName, "pcf"))
 
211
        return TYPE_PCF;
 
212
 
 
213
    if(Misc::checkExt(fileName, "bdf"))
 
214
        return TYPE_BDF;
 
215
 
 
216
    if(Misc::checkExt(fileName, "afm"))
 
217
        return TYPE_AFM;
 
218
 
 
219
    return TYPE_UNKNOWN;
 
220
}
 
221
 
 
222
QString & CFontEngine::fixFoundry(QString &foundry)
 
223
{
 
224
    // Try to make foundry similar to that of AFMs...
 
225
    if(foundry==QString::fromLatin1("ibm"))
 
226
        foundry=QString::fromLatin1("IBM");
 
227
    else if(foundry==QString::fromLatin1("urw"))
 
228
        foundry=QString::fromLatin1("URW");
 
229
    else if(foundry==QString::fromLatin1("itc"))
 
230
        foundry=QString::fromLatin1("ITC");
 
231
    else if(foundry==QString::fromLatin1("nec"))
 
232
        foundry=QString::fromLatin1("NEC");
 
233
    else if(foundry==QString::fromLatin1("b&h"))
 
234
        foundry=QString::fromLatin1("B&H");
 
235
    else
 
236
    {
 
237
        QChar *ch(foundry.data());
 
238
        int   len(foundry.length());
 
239
        bool  isSpace(true);
 
240
 
 
241
        while(len--)
 
242
        {
 
243
            if (isSpace)
 
244
                *ch=ch->toUpper();
 
245
 
 
246
            isSpace=ch->isSpace();
 
247
            ++ch;
 
248
        }
 
249
    }
 
250
 
 
251
    return foundry;
 
252
}
 
253
 
 
254
bool CFontEngine::openFont(EType type, QByteArray &in, const char *fileName, int face)
 
255
{
 
256
    bool ok=false;
 
257
 
 
258
    closeFont();
 
259
 
 
260
    itsWeight=FC_WEIGHT_MEDIUM;
 
261
    itsWidth=FC_WIDTH_NORMAL;
 
262
    itsSpacing=FC_PROPORTIONAL;
 
263
    itsItalic=FC_SLANT_ROMAN;
 
264
    itsFamily=itsFoundry=itsVersion=QString();
 
265
 
 
266
    if(in.size()<=0 && fileName && TYPE_UNKNOWN==type)
 
267
        type=getType(fileName); // Read file header to obtain type...
 
268
 
 
269
    switch(type)
 
270
    {
 
271
        default:
 
272
            ok=openFontFt(in, fileName, face, TYPE_TYPE1==type);
 
273
            break;
 
274
#ifndef HAVE_FcFreeTypeQueryFace
 
275
        case TYPE_PCF:
 
276
            ok=openFontPcf(in);
 
277
            break;
 
278
        case TYPE_BDF:
 
279
            ok=openFontBdf(in);
 
280
            break;
 
281
#endif
 
282
        case TYPE_AFM:
 
283
            ok=openFontAfm(in);
 
284
        case TYPE_UNKNOWN:
 
285
            break;
 
286
    }
 
287
 
 
288
    return ok;
 
289
}
 
290
 
 
291
void CFontEngine::closeFont()
 
292
{
 
293
    if(itsFt.open)
 
294
    {
 
295
        FT_Done_Face(itsFt.face);
 
296
        itsFt.open=false;
 
297
    }
 
298
}
 
299
 
 
300
static int strToWeight(const QString &str)
 
301
{
 
302
    if(str.isEmpty())
 
303
        return FC_WEIGHT_MEDIUM;
 
304
    else if(str.contains("Bold", Qt::CaseInsensitive))
 
305
        return FC_WEIGHT_BOLD;
 
306
    else if(str.contains("Heavy", Qt::CaseInsensitive))
 
307
        return FC_WEIGHT_HEAVY;
 
308
    else if(str.contains("Black", Qt::CaseInsensitive))
 
309
        return FC_WEIGHT_BLACK;
 
310
    else if(str.contains("ExtraBold", Qt::CaseInsensitive))
 
311
        return FC_WEIGHT_EXTRABOLD;
 
312
    else if(str.contains("UltraBold", Qt::CaseInsensitive))
 
313
        return FC_WEIGHT_ULTRABOLD;
 
314
    else if(str.contains("ExtraLight", Qt::CaseInsensitive))
 
315
        return FC_WEIGHT_EXTRALIGHT;
 
316
    else if(str.contains("UltraLight", Qt::CaseInsensitive))
 
317
        return FC_WEIGHT_ULTRALIGHT;
 
318
    else if(str.contains("Light", Qt::CaseInsensitive))
 
319
        return FC_WEIGHT_LIGHT;
 
320
    else if(str.contains("Medium", Qt::CaseInsensitive) ||
 
321
                    str.contains("Normal", Qt::CaseInsensitive) ||
 
322
                    str.contains("Roman", Qt::CaseInsensitive))
 
323
        return FC_WEIGHT_MEDIUM;
 
324
    else if(str.contains("Regular", Qt::CaseInsensitive))
 
325
        return FC_WEIGHT_REGULAR;
 
326
    else if(str.contains("SemiBold", Qt::CaseInsensitive))
 
327
        return FC_WEIGHT_SEMIBOLD;
 
328
    else if(str.contains("DemiBold", Qt::CaseInsensitive))
 
329
        return FC_WEIGHT_DEMIBOLD;
 
330
    else if(str.contains("Thin", Qt::CaseInsensitive))
 
331
        return FC_WEIGHT_THIN;
 
332
    else if(str.contains("Book", Qt::CaseInsensitive))
 
333
        return FC_WEIGHT_NORMAL;
 
334
    else if(str.contains("Demi", Qt::CaseInsensitive))
 
335
        return FC_WEIGHT_NORMAL;
 
336
    else
 
337
        return FC_WEIGHT_MEDIUM;
 
338
}
 
339
 
 
340
static int strToWidth(const QString &str)
 
341
{
 
342
    if(str.isEmpty())
 
343
        return KFI_FC_WIDTH_NORMAL;
 
344
    else if(str.contains("UltraCondensed", Qt::CaseInsensitive))
 
345
        return KFI_FC_WIDTH_ULTRACONDENSED;
 
346
    else if(str.contains("ExtraCondensed", Qt::CaseInsensitive))
 
347
        return KFI_FC_WIDTH_EXTRACONDENSED;
 
348
    else if(str.contains("SemiCondensed", Qt::CaseInsensitive))
 
349
        return KFI_FC_WIDTH_SEMICONDENSED;
 
350
    else if(str.contains("Condensed", Qt::CaseInsensitive))
 
351
        return KFI_FC_WIDTH_CONDENSED;
 
352
    else if(str.contains("SemiExpanded", Qt::CaseInsensitive))
 
353
        return KFI_FC_WIDTH_SEMIEXPANDED;
 
354
    else if(str.contains("UltraExpanded", Qt::CaseInsensitive))
 
355
        return KFI_FC_WIDTH_ULTRAEXPANDED;
 
356
    else if(str.contains("ExtraExpanded", Qt::CaseInsensitive))
 
357
        return KFI_FC_WIDTH_EXTRAEXPANDED;
 
358
    else if(str.contains("Expanded", Qt::CaseInsensitive))
 
359
        return KFI_FC_WIDTH_EXPANDED;
 
360
    else
 
361
        return KFI_FC_WIDTH_NORMAL;
 
362
}
 
363
 
 
364
static int checkItalic(int it, const QString &full)
 
365
{
 
366
    return (FC_SLANT_ITALIC==it && (-1!=full.indexOf("Oblique") || -1!=full.indexOf("Slanted")))
 
367
           ? FC_SLANT_OBLIQUE
 
368
           : it;
 
369
}
 
370
 
 
371
static const char * getFoundry(const char *notice)
 
372
{
 
373
    struct Map
 
374
    {
 
375
        const char *noticeStr,
 
376
                   *foundry;
 
377
    };
 
378
 
 
379
    static const Map map[]=
 
380
    {
 
381
        { "Bigelow",                            "B&H"},
 
382
        { "Adobe",                              "Adobe"},
 
383
        { "Bitstream",                          "Bitstream"},
 
384
        { "Monotype",                           "Monotype"},
 
385
        { "Linotype",                           "Linotype"},
 
386
        { "LINOTYPE-HELL",                      "Linotype"},
 
387
        { "IBM",                                "IBM"},
 
388
        { "URW",                                "URW"},
 
389
        { "International Typeface Corporation", "ITC"},
 
390
        { "Tiro Typeworks",                     "Tiro"},
 
391
        { "XFree86",                            "XFree86"},
 
392
        { "Microsoft",                          "Microsoft"},
 
393
        { "Omega",                              "Omega"},
 
394
        { "Font21",                             "Hwan"},
 
395
        { "HanYang System",                     "Hanyang"},
 
396
        { NULL,                                 NULL }
 
397
    };
 
398
 
 
399
    const Map *entry;
 
400
 
 
401
    if(notice)
 
402
        for(entry=map; NULL!=entry->foundry; entry++)
 
403
            if(strstr(notice, entry->noticeStr)!=NULL)
 
404
                return entry->foundry;
 
405
 
 
406
    return NULL;
 
407
}
 
408
 
 
409
#ifndef HAVE_FcFreeTypeQueryFace
 
410
static bool lookupName(FT_Face face, int nid, int pid, int eid, FT_SfntName *nameReturn)
 
411
{
 
412
    int n = FT_Get_Sfnt_Name_Count(face);
 
413
 
 
414
    if(n>0)
 
415
    {
 
416
        int         i;
 
417
        FT_SfntName name;
 
418
 
 
419
        for(i=0; i<n; i++)
 
420
            if(0==FT_Get_Sfnt_Name(face, i, &name) && name.name_id == nid && name.platform_id == pid &&
 
421
               (eid < 0 || name.encoding_id == eid))
 
422
            {
 
423
                switch(name.platform_id)
 
424
                {
 
425
                    case TT_PLATFORM_APPLE_UNICODE:
 
426
                    case TT_PLATFORM_MACINTOSH:
 
427
                        if(name.language_id != TT_MAC_LANGID_ENGLISH)
 
428
                            continue;
 
429
                        break;
 
430
                    case TT_PLATFORM_MICROSOFT:
 
431
                        if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES &&
 
432
                           name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM)
 
433
                            continue;
 
434
                        break;
 
435
                    default:
 
436
                        continue;
 
437
                }
 
438
 
 
439
                if(name.string_len > 0)
 
440
                {
 
441
                    *nameReturn = name;
 
442
                    return true;
 
443
                }
 
444
            }
 
445
    }
 
446
 
 
447
    return false;
 
448
}
 
449
 
 
450
static QByteArray getName(FT_Face face, int nid)
 
451
{
 
452
    FT_SfntName name;
 
453
    QByteArray  str;
 
454
 
 
455
    if(lookupName(face, nid, TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) ||
 
456
       lookupName(face, nid, TT_PLATFORM_APPLE_UNICODE, -1, &name))
 
457
        for(unsigned int i=0; i < name.string_len / 2; i++)
 
458
            str+=0 == name.string[2*i] ? name.string[(2*i)+1] : '_';
 
459
    else if(lookupName(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, &name)) // Pretend that Apple Roman is ISO 8859-1
 
460
        for(unsigned int i=0; i < name.string_len; i++)
 
461
            str+=name.string[i];
 
462
 
 
463
    return str;
 
464
}
 
465
 
 
466
static const char * getFoundry(const FT_Face face, TT_OS2 *os2)
 
467
{
 
468
    struct Map
 
469
    {
 
470
        const char *vendorId,
 
471
                   *foundry;
 
472
    };
 
473
 
 
474
    static const int constVendLen=4;
 
475
 
 
476
    // These are taken from ttmkfdir
 
477
    static const Map map[]=
 
478
    {
 
479
        { "ADBE", "Adobe"},
 
480
        { "AGFA", "Agfa"},
 
481
        { "ALTS", "Altsys"},
 
482
        { "APPL", "Apple"},
 
483
        { "ARPH", "Arphic"},
 
484
        { "ATEC", "Alltype"},
 
485
        { "B&H",  "B&H"},
 
486
        { "BITS", "Bitstream"},
 
487
        { "CANO", "Cannon"},
 
488
        { "DYNA", "DynaLab"},
 
489
        { "EPSN", "Epson"},
 
490
        { "FJ",   "Fujitsu"},
 
491
        { "IBM",  "IBM"},
 
492
        { "ITC",  "ITC"},
 
493
        { "IMPR", "Impress"},
 
494
        { "LARA", "Larabie"},
 
495
        { "LEAF", "Interleaf"},
 
496
        { "LETR", "letraset"},
 
497
        { "LINO", "Linotype"},
 
498
        { "MACR", "Macromedia"},
 
499
        { "MONO", "Monotype"},
 
500
        { "MS",   "Microsoft"},
 
501
        { "MT",   "Monotype"},
 
502
        { "NEC",  "NEC"},
 
503
        { "PARA", "ParaType"},
 
504
        { "QMSI", "QMS"},
 
505
        { "RICO", "Ricoh"},
 
506
        { "URW",  "URW"},
 
507
        { "Y&Y" , "Z&Y"},
 
508
        { NULL  ,  NULL}
 
509
    };
 
510
 
 
511
    static char vendor[constVendLen+1];
 
512
 
 
513
    vendor[0]='\0';
 
514
 
 
515
    if(NULL!=os2 && 0xFFFF!=os2->version)
 
516
    {
 
517
        const Map *entry;
 
518
        char      vend[constVendLen+1];
 
519
 
 
520
        strncpy(vendor, (const char *)(os2->achVendID), constVendLen);
 
521
        vendor[constVendLen]='\0';
 
522
 
 
523
        for(int i=0; i<constVendLen; ++i)
 
524
            vend[i]=toupper(vendor[i]);
 
525
 
 
526
        for(entry=map; NULL!=entry->vendorId; entry++)
 
527
        {
 
528
            unsigned int len=strlen(entry->vendorId);
 
529
 
 
530
            if(0==memcmp(entry->vendorId, vend, len))
 
531
            {
 
532
                bool ok=true;
 
533
 
 
534
                for(int i=len; i<constVendLen && ok; i++)
 
535
                    if(vend[i]!=' ' && entry->vendorId[i]!='\0')
 
536
                        ok=false;
 
537
 
 
538
                if(ok)
 
539
                    return entry->foundry;
 
540
            }
 
541
        }
 
542
    }
 
543
 
 
544
    const char *foundry=NULL;
 
545
 
 
546
    if(!foundry)
 
547
        foundry=getFoundry(getName(face, TT_NAME_ID_TRADEMARK));
 
548
 
 
549
    if(!foundry)
 
550
        foundry=getFoundry(getName(face, TT_NAME_ID_MANUFACTURER));
 
551
 
 
552
    if(!foundry && vendor[0] && !isspace(vendor[0]) && '-'!=vendor[0])  // Some fonts have a totally blank vendor field
 
553
    {
 
554
       int i;
 
555
 
 
556
        // Remove any dashes...
 
557
        for(int i=constVendLen-1; i>0; i--)
 
558
            if('-'==vendor[i])
 
559
                vendor[i]=' ';
 
560
 
 
561
        // Strip any trailing whitepace
 
562
        for(i=constVendLen-1; i>0; i--)
 
563
            if(isspace(vendor[i]))
 
564
               vendor[i]='\0';
 
565
            else
 
566
               break;
 
567
 
 
568
        foundry=vendor;
 
569
    }
 
570
 
 
571
    return foundry ;
 
572
}
 
573
#endif
 
574
 
 
575
bool CFontEngine::openFontFt(QByteArray &in, const char *fileName, int face, bool type1)
 
576
{
 
577
    bool status=in.size()<=0
 
578
            ? FT_New_Face(itsFt.library, fileName, face, &itsFt.face) ? false : true
 
579
            : openFtFace(itsFt.library, in, face, &itsFt.face) ? false : true;
 
580
 
 
581
    if(status)
 
582
        itsFt.open=true;
 
583
 
 
584
    if(status)
 
585
    {
 
586
        PS_FontInfoRec t1info;
 
587
 
 
588
        if(type1)
 
589
            FT_Get_PS_Font_Info(itsFt.face, &t1info);
 
590
 
 
591
#ifdef HAVE_FcFreeTypeQueryFace
 
592
        FcPattern *pat=FcFreeTypeQueryFace(itsFt.face, (FcChar8*) fileName, face, NULL);
 
593
 
 
594
        itsWeight=FC_WEIGHT_REGULAR;
 
595
        itsWidth=KFI_FC_WIDTH_NORMAL;
 
596
        itsSpacing=FC_PROPORTIONAL;
 
597
 
 
598
        if(pat)
 
599
        {
 
600
            itsFamily=FC::getFcString(pat, FC_FAMILY, face);
 
601
            FcPatternGetInteger(pat, FC_WEIGHT, face, &itsWeight);
 
602
#ifndef KFI_FC_NO_WIDTHS
 
603
            FcPatternGetInteger(pat, FC_WIDTH, face, &itsWidth);
 
604
#endif
 
605
            FcPatternGetInteger(pat, FC_SLANT, face, &itsItalic);
 
606
            FcPatternGetInteger(pat, FC_SPACING, face, &itsSpacing);
 
607
            itsFoundry=FC::getFcString(pat, FC_FOUNDRY, face);
 
608
 
 
609
            if(type1)
 
610
                itsVersion=t1info.version;
 
611
            else
 
612
            {
 
613
                int version;
 
614
 
 
615
                FcPatternGetInteger(pat, FC_FONTVERSION, face, &version);
 
616
                if(version>0)
 
617
                    itsVersion.setNum(decodeFixed(version));
 
618
            }
 
619
 
 
620
            FcPatternDestroy(pat);
 
621
            fixFoundry(itsFoundry);
 
622
        }
 
623
        else
 
624
            status=false;
 
625
 
 
626
#else
 
627
 
 
628
        enum ETtfWidth
 
629
        {
 
630
            TTF_WIDTH_ULTRA_CONDENSED = 1,
 
631
            TTF_WIDTH_EXTRA_CONDENSED = 2,
 
632
            TTF_WIDTH_CONDENSED       = 3,
 
633
            TTF_WIDTH_SEMI_CONDENSED  = 4,
 
634
            TTF_WIDTH_NORMAL          = 5,
 
635
            TTF_WIDTH_SEMI_EXPANDED   = 6,
 
636
            TTF_WIDTH_EXPANDED        = 7,
 
637
            TTF_WIDTH_EXTRA_EXPANDED  = 8,
 
638
            TTF_WIDTH_ULTRA_EXPANDED  = 9
 
639
        };
 
640
 
 
641
        QString fullName;
 
642
 
 
643
        if(type1)
 
644
        {
 
645
            fullName=t1info.full_name;
 
646
            itsFamily=t1info.family_name;
 
647
        }
 
648
        else
 
649
        {
 
650
            fullName=getName(itsFt.face, TT_NAME_ID_FULL_NAME);
 
651
            itsFamily=getName(itsFt.face, TT_NAME_ID_FONT_FAMILY);
 
652
        }
 
653
 
 
654
        if(itsFamily.isEmpty())
 
655
            if(fullName.isEmpty())
 
656
                itsFamily=fullName=FT_Get_Postscript_Name(itsFt.face);
 
657
            else
 
658
                itsFamily=fullName;
 
659
        else
 
660
            if(fullName.isEmpty())
 
661
                fullName=itsFamily;
 
662
 
 
663
        if(fullName.isEmpty())
 
664
            status=false;   // Hmm... couldn't find any of the names!
 
665
 
 
666
        if(status)
 
667
        {
 
668
            if(type1)
 
669
            {
 
670
                itsWeight=strToWeight(t1info.weight);
 
671
                itsItalic=t1info.italic_angle <= -4 || t1info.italic_angle >= 4 ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
 
672
                itsWidth=strToWidth(fullName);
 
673
                itsItalic=checkItalic(itsItalic, fullName);
 
674
                itsSpacing=t1info.is_fixed_pitch ? FC_MONO : FC_PROPORTIONAL;
 
675
                itsFoundry=KFI::getFoundry(t1info.notice);
 
676
                itsVersion=t1info.version;
 
677
            }
 
678
            else // TrueType...
 
679
            {
 
680
                #define WEIGHT_UNKNOWN 0xFFFF
 
681
                #define WIDTH_UNKNOWN  0xFFFF
 
682
 
 
683
                TT_Postscript *post=(TT_Postscript *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_post);
 
684
                TT_OS2        *os2=(TT_OS2 *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_os2);
 
685
                TT_Header     *head=(TT_Header *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_head);
 
686
                bool          gotItalic=false;
 
687
 
 
688
                itsWidth=WIDTH_UNKNOWN;
 
689
                itsWeight=WEIGHT_UNKNOWN;
 
690
 
 
691
                if(NULL!=os2 && 0xFFFF!=os2->version)
 
692
                {
 
693
                    if (os2->usWeightClass == 0)
 
694
                        ;
 
695
                    else if (os2->usWeightClass < 150)
 
696
                        itsWeight=FC_WEIGHT_THIN;
 
697
                    else if (os2->usWeightClass < 250)
 
698
                        itsWeight=FC_WEIGHT_EXTRALIGHT;
 
699
                    else if (os2->usWeightClass < 350)
 
700
                        itsWeight=FC_WEIGHT_LIGHT;
 
701
                    else if (os2->usWeightClass < 450)
 
702
                        itsWeight=FC_WEIGHT_REGULAR;
 
703
                    else if (os2->usWeightClass < 550)
 
704
                        itsWeight=FC_WEIGHT_MEDIUM;
 
705
                    else if (os2->usWeightClass < 650)
 
706
                        itsWeight=FC_WEIGHT_SEMIBOLD;
 
707
                    else if (os2->usWeightClass < 750)
 
708
                        itsWeight=FC_WEIGHT_BOLD;
 
709
                    else if (os2->usWeightClass < 850)
 
710
                        itsWeight=FC_WEIGHT_EXTRABOLD;
 
711
                    else if (os2->usWeightClass < 950)
 
712
                        itsWeight=FC_WEIGHT_BLACK;
 
713
 
 
714
                    switch(os2->usWidthClass)
 
715
                    {
 
716
                        case TTF_WIDTH_ULTRA_CONDENSED:
 
717
                            itsWidth=FC_WIDTH_ULTRACONDENSED;
 
718
                            break;
 
719
                        case TTF_WIDTH_EXTRA_CONDENSED:
 
720
                            itsWidth=FC_WIDTH_EXTRACONDENSED;
 
721
                            break;
 
722
                        case TTF_WIDTH_CONDENSED:
 
723
                            itsWidth=FC_WIDTH_CONDENSED;
 
724
                            break;
 
725
                        case TTF_WIDTH_SEMI_CONDENSED:
 
726
                            itsWidth=FC_WIDTH_SEMICONDENSED;
 
727
                            break;
 
728
                        case TTF_WIDTH_NORMAL:
 
729
                            itsWidth=FC_WIDTH_NORMAL;
 
730
                            break;
 
731
                        case TTF_WIDTH_SEMI_EXPANDED:
 
732
                            itsWidth=FC_WIDTH_SEMIEXPANDED;
 
733
                            break;
 
734
                        case TTF_WIDTH_EXPANDED:
 
735
                            itsWidth=FC_WIDTH_EXPANDED;
 
736
                            break;
 
737
                        case TTF_WIDTH_EXTRA_EXPANDED:
 
738
                            itsWidth=FC_WIDTH_EXTRAEXPANDED;
 
739
                            break;
 
740
                        case TTF_WIDTH_ULTRA_EXPANDED:
 
741
                            itsWidth=FC_WIDTH_ULTRAEXPANDED;
 
742
                            break;
 
743
                    }
 
744
 
 
745
                    itsItalic=os2->fsSelection&(1 << 0) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
 
746
                    gotItalic=true;
 
747
                }
 
748
 
 
749
                if(WEIGHT_UNKNOWN==itsWeight)
 
750
                    itsWeight=itsFt.face->style_flags&FT_STYLE_FLAG_BOLD
 
751
                                ? FC_WEIGHT_BOLD
 
752
                                : FC_WEIGHT_MEDIUM;
 
753
 
 
754
                if(WIDTH_UNKNOWN==itsWidth)
 
755
                    itsWidth=FC_WIDTH_NORMAL;
 
756
 
 
757
                if(!gotItalic && head!=NULL)
 
758
                {
 
759
                    gotItalic=true;
 
760
                    itsItalic=head->Mac_Style & 2 ? FC_SLANT_ITALIC : FC_SLANT_ROMAN;
 
761
                }
 
762
 
 
763
                if(head)
 
764
                {
 
765
                    double version=decodeFixed(head->Font_Revision);
 
766
 
 
767
                    if(version>0)
 
768
                        itsVersion.setNum(version);
 
769
                }
 
770
 
 
771
                if(!gotItalic && NULL!=post)
 
772
                {
 
773
                    gotItalic=true;
 
774
                    itsItalic=0.0f==decodeFixed(post->italicAngle) ? FC_SLANT_ROMAN : FC_SLANT_ITALIC;
 
775
                }
 
776
 
 
777
                itsItalic=checkItalic(itsItalic, fullName);
 
778
 
 
779
                if(NULL!=post &&  post->isFixedPitch)
 
780
                {
 
781
                    TT_HoriHeader *hhea=NULL;
 
782
 
 
783
                    if(NULL!=(hhea=(TT_HoriHeader *)FT_Get_Sfnt_Table(itsFt.face, ft_sfnt_hhea)) &&
 
784
                    hhea->min_Left_Side_Bearing >= 0 && hhea->xMax_Extent <= hhea->advance_Width_Max)
 
785
                        itsSpacing=FC_CHARCELL;
 
786
                    else
 
787
                        itsSpacing=FC_MONO;
 
788
                }
 
789
                else
 
790
                    itsSpacing=FC_PROPORTIONAL;
 
791
 
 
792
                itsFoundry=KFI::getFoundry(itsFt.face, os2);
 
793
            }
 
794
        }
 
795
#endif
 
796
    }
 
797
    if(!status)
 
798
        closeFont();
 
799
 
 
800
    return status;
 
801
}
 
802
 
 
803
bool CFontEngine::openFontAfm(QByteArray &in)
 
804
{
 
805
    bool        inMetrics=false;
 
806
    QString     full;
 
807
    QTextStream ds(&in, QIODevice::ReadOnly);
 
808
 
 
809
    while(!ds.atEnd())
 
810
    {
 
811
        QString line(ds.readLine());
 
812
        line=line.simplified();
 
813
 
 
814
        if(inMetrics)
 
815
        {
 
816
            if(0==line.indexOf("FullName "))
 
817
            {
 
818
                full=line.mid(9);
 
819
                itsWidth=strToWidth(full);
 
820
            }
 
821
            else if(0==line.indexOf("FamilyName "))
 
822
                itsFamily=line.mid(11);
 
823
            else if(0==line.indexOf("Weight "))
 
824
                itsWeight=strToWeight(line.mid(7));
 
825
            else if(0==line.indexOf("ItalicAngle "))
 
826
                itsItalic=0.0f==line.mid(12).toFloat() ? FC_SLANT_ROMAN : FC_SLANT_ITALIC;
 
827
            else if(0==line.indexOf("IsFixedPitch "))
 
828
                itsSpacing= ( line.mid(13).contains("false", Qt::CaseInsensitive)
 
829
                            ? FC_PROPORTIONAL : FC_MONO );
 
830
            else if(0==line.indexOf("Notice "))
 
831
                itsFoundry=KFI::getFoundry(line.mid(7).toLatin1());
 
832
             else if(0==line.indexOf("Version "))
 
833
                 itsVersion=line.mid(8);
 
834
            else if(0==line.indexOf("StartCharMetrics"))
 
835
                break;
 
836
        }
 
837
        else
 
838
            if(0==line.indexOf("StartFontMetrics"))
 
839
                inMetrics=true;
 
840
    };
 
841
 
 
842
    if(itsFamily.isEmpty() && !full.isEmpty())
 
843
        itsFamily=full;
 
844
 
 
845
    checkItalic(itsItalic, full);
 
846
 
 
847
    return !full.isEmpty() && !itsFamily.isEmpty();
 
848
}
 
849
 
 
850
#ifndef HAVE_FcFreeTypeQueryFace
 
851
static int charToItalic(char c)
 
852
{
 
853
    switch(c)
 
854
    {
 
855
        case 'i':
 
856
        case 'I':
 
857
            return FC_SLANT_ITALIC;
 
858
        case 'o':
 
859
        case 'O':
 
860
            return FC_SLANT_OBLIQUE;
 
861
        case 'r':
 
862
        case 'R':
 
863
        default:
 
864
            return FC_SLANT_ROMAN;
 
865
    }
 
866
}
 
867
 
 
868
static int charToSpacing(char c)
 
869
{
 
870
    switch(c)
 
871
    {
 
872
        case 'm':
 
873
        case 'M':
 
874
            return FC_MONO;
 
875
        case 'c':
 
876
        case 'C':
 
877
            return FC_CHARCELL;
 
878
        default:
 
879
        case 'p':
 
880
        case 'P':
 
881
            return FC_PROPORTIONAL;
 
882
    }
 
883
}
 
884
 
 
885
void CFontEngine::parseXlfdBmp(const QString &xlfd)
 
886
{
 
887
    enum EXlfd
 
888
    {
 
889
        XLFD_FOUNDRY=0,
 
890
        XLFD_FAMILY,
 
891
        XLFD_WEIGHT,
 
892
        XLFD_SLANT,
 
893
        XLFD_WIDTH,
 
894
        XLFD_STYLE,
 
895
        XLFD_PIXEL_SIZE,
 
896
        XLFD_POINT_SIZE,
 
897
        XLFD_RESX,
 
898
        XLFD_RESY,
 
899
        XLFD_SPACING,
 
900
        XLFD_AV_WIDTH,
 
901
        XLFD_ENCODING,
 
902
        XLFD_END
 
903
    };
 
904
 
 
905
    int     pos=0,
 
906
            oldPos=1;
 
907
    int     entry;
 
908
 
 
909
    // XLFD:
 
910
    //     -foundry-family-weight-slant-width-?-pixelSize-pointSize-resX-resY-spacing-avWidth-csReg-csEnc
 
911
    for(entry=XLFD_FOUNDRY; -1!=(pos=xlfd.indexOf('-', pos+1)) && entry<XLFD_END; ++entry)
 
912
    {
 
913
        switch(entry)
 
914
        {
 
915
            default:
 
916
                break;
 
917
            case XLFD_FOUNDRY:
 
918
                itsFoundry=xlfd.mid(oldPos, pos-oldPos);
 
919
                break;
 
920
            case XLFD_FAMILY:
 
921
                itsFamily=xlfd.mid(oldPos, pos-oldPos);
 
922
                break;
 
923
            case XLFD_WEIGHT:
 
924
                itsWeight=strToWeight(xlfd.mid(oldPos, pos-oldPos).toLocal8Bit());
 
925
                break;
 
926
            case XLFD_SLANT:
 
927
                if(pos>0)
 
928
                    itsItalic=charToItalic(xlfd[pos-1].toLatin1());
 
929
                break;
 
930
            case XLFD_WIDTH:
 
931
                itsWidth=strToWidth(xlfd.mid(oldPos, pos-oldPos));
 
932
                break;
 
933
            case XLFD_STYLE:
 
934
            case XLFD_PIXEL_SIZE:
 
935
            case XLFD_POINT_SIZE:
 
936
            case XLFD_RESX:
 
937
            case XLFD_RESY:
 
938
                break;
 
939
            case XLFD_SPACING:
 
940
                if(pos>0)
 
941
                    itsSpacing=charToSpacing(xlfd[pos-1].toLatin1());
 
942
                break;
 
943
            case XLFD_AV_WIDTH:
 
944
            case XLFD_ENCODING:
 
945
                break;
 
946
        }
 
947
 
 
948
        oldPos=pos+1;
 
949
    }
 
950
}
 
951
 
 
952
bool CFontEngine::openFontBdf(QByteArray &in)
 
953
{
 
954
    QTextStream ds(&in, QIODevice::ReadOnly);
 
955
 
 
956
    ds.readLine(); // Skip 1st line.
 
957
    while(!ds.atEnd())
 
958
    {
 
959
        QString line(ds.readLine());
 
960
 
 
961
        if(0==line.indexOf("FONT ", Qt::CaseInsensitive))
 
962
        {
 
963
            parseXlfdBmp(line.mid(5));
 
964
            return true;
 
965
        }
 
966
    }
 
967
 
 
968
    return false;
 
969
}
 
970
 
 
971
static unsigned int readLsb32(QBuffer &in)
 
972
{
 
973
    unsigned char num[4];
 
974
 
 
975
    return 4==in.read((char *)num, 4)
 
976
            ? (num[0])+(num[1]<<8)+(num[2]<<16)+(num[3]<<24)
 
977
            : 0;
 
978
}
 
979
 
 
980
static unsigned int read32(QBuffer &in, bool msb)
 
981
{
 
982
    if(msb)
 
983
    {
 
984
        unsigned char num[4];
 
985
 
 
986
        return 4==in.read((char *)num, 4)
 
987
                ? (num[0]<<24)+(num[1]<<16)+(num[2]<<8)+(num[3])
 
988
                : 0;
 
989
    }
 
990
 
 
991
    return readLsb32(in);
 
992
}
 
993
 
 
994
static const unsigned int constBitmapMaxProps=1024;
 
995
 
 
996
bool CFontEngine::openFontPcf(QByteArray &in)
 
997
{
 
998
    bool               foundXlfd=false;
 
999
    const unsigned int contPcfVersion=(('p'<<24)|('c'<<16)|('f'<<8)|1);
 
1000
    QBuffer            buf;
 
1001
 
 
1002
    buf.setBuffer(&in);
 
1003
    buf.open(QIODevice::ReadOnly);
 
1004
 
 
1005
    if(contPcfVersion==readLsb32(buf))
 
1006
    {
 
1007
        const unsigned int constPropertiesType=1;
 
1008
 
 
1009
        unsigned int numTables=readLsb32(buf),
 
1010
                     table,
 
1011
                     type,
 
1012
                     format,
 
1013
                     size,
 
1014
                     offset;
 
1015
 
 
1016
        for(table=0; table<numTables && !buf.atEnd() && !foundXlfd; ++table)
 
1017
        {
 
1018
            type=readLsb32(buf);
 
1019
            format=readLsb32(buf);
 
1020
            size=readLsb32(buf);
 
1021
            offset=readLsb32(buf);
 
1022
            if(constPropertiesType==type)
 
1023
            {
 
1024
                if(buf.seek(offset))
 
1025
                {
 
1026
                    const unsigned int constFormatMask=0xffffff00;
 
1027
 
 
1028
                    format=readLsb32(buf);
 
1029
                    if(0==(format&constFormatMask))
 
1030
                    {
 
1031
                        const unsigned int constByteMask=0x4;
 
1032
 
 
1033
                        bool         msb=format&constByteMask;
 
1034
                        unsigned int numProps=read32(buf, msb);
 
1035
 
 
1036
                        if(numProps>0 && numProps<constBitmapMaxProps)
 
1037
                        {
 
1038
                            unsigned int strSize,
 
1039
                                         skip;
 
1040
 
 
1041
                            struct TProp
 
1042
                            {
 
1043
                                unsigned int name,
 
1044
                                             value;
 
1045
                                bool         isString;
 
1046
                            } *props=new struct TProp [numProps];
 
1047
 
 
1048
                            if(props)
 
1049
                            {
 
1050
                                char           tmp;
 
1051
                                unsigned short prop;
 
1052
 
 
1053
                                for(prop=0; prop<numProps; ++prop)
 
1054
                                {
 
1055
                                    props[prop].name=read32(buf, msb);
 
1056
                                    buf.read(&tmp, 1);
 
1057
                                    props[prop].isString=tmp ? true : false;
 
1058
                                    props[prop].value=read32(buf, msb);
 
1059
                                }
 
1060
 
 
1061
                                skip=4-((numProps*9)%4);
 
1062
                                if(skip!=4)
 
1063
                                    buf.seek(buf.pos()+skip);
 
1064
 
 
1065
                                strSize=read32(buf, msb);
 
1066
 
 
1067
                                if(strSize>0)
 
1068
                                {
 
1069
                                    QByteArray str=buf.read(strSize);
 
1070
 
 
1071
                                    if(str.size()==(int)strSize)
 
1072
                                    {
 
1073
                                        // Finally we have the data............
 
1074
                                        const int constMaxStrLen=1024;
 
1075
 
 
1076
                                        char tmp[constMaxStrLen];
 
1077
 
 
1078
                                        for(prop=0; prop<numProps && !foundXlfd; ++prop)
 
1079
                                            if(kasciistricmp(&(str.data()[props[prop].name]), "FONT")==0)
 
1080
                                            {
 
1081
                                                if(props[prop].isString && strlen(&(str.data()[props[prop].value])))
 
1082
                                                {
 
1083
                                                    foundXlfd=true;
 
1084
                                                    strncpy(tmp, &(str.data()[props[prop].value]), constMaxStrLen);
 
1085
                                                    tmp[constMaxStrLen-1]='\0';
 
1086
                                                    parseXlfdBmp(tmp);
 
1087
                                                }
 
1088
                                                break;
 
1089
                                            }
 
1090
                                    }
 
1091
                                }
 
1092
                                delete [] props;
 
1093
                            }
 
1094
                        }
 
1095
                    }
 
1096
                }
 
1097
                break;   // Forget the other tables...
 
1098
            }
 
1099
        }
 
1100
    }
 
1101
 
 
1102
    return foundXlfd;
 
1103
}
 
1104
#endif
 
1105
 
 
1106
CFontEngine::TFtData::TFtData()
 
1107
                    : open(false)
 
1108
{
 
1109
    if(FT_Init_FreeType(&library))
 
1110
    {
 
1111
        std::cerr << "ERROR: FreeType2 failed to initialise\n";
 
1112
        exit(0);
 
1113
    }
 
1114
}
 
1115
 
 
1116
CFontEngine::TFtData::~TFtData()
 
1117
{
 
1118
    FT_Done_FreeType(library);
 
1119
}
 
1120
 
 
1121
}