~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/gui/text/qfontengine_x11.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-10-12 23:14:14 UTC
  • mto: (15.1.1 lenny) (1.3.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 16.
  • Revision ID: james.westby@ubuntu.com-20061012231414-y2oqbom5dy389os0
Tags: upstream-4.2.0
ImportĀ upstreamĀ versionĀ 4.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
#include "qwidget.h"
37
37
#include "qsettings.h"
38
38
#include "qfile.h"
 
39
#include "qabstractfileengine.h"
39
40
 
40
41
#include <private/qpaintengine_x11_p.h>
41
42
#include "qfont.h"
46
47
 
47
48
#include <private/qpainter_p.h>
48
49
#include <private/qunicodetables_p.h>
 
50
#include <private/qpdf_p.h>
49
51
 
50
52
#include <private/qt_x11_p.h>
51
53
#include "qx11info_x11.h"
60
62
#include FT_OUTLINE_H
61
63
#include FT_TRUETYPE_TABLES_H
62
64
#include FT_TYPE1_TABLES_H
 
65
#include FT_GLYPH_H
63
66
 
64
67
/*
65
68
 * Freetype 2.1.7 and earlier used width/height
84
87
 
85
88
struct QFreetypeFace
86
89
{
87
 
    void computeSize(const QFontDef &fontDef, int *xsize, int *ysize);
 
90
    void computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing);
88
91
    QFontEngine::Properties properties() const;
89
92
    QByteArray getSfntTable(uint tag) const;
90
93
 
121
124
    ~QFreetypeFace() {}
122
125
    QAtomic ref;
123
126
    QAtomic _lock;
 
127
    QByteArray fontData;
124
128
};
125
129
 
126
130
static FT_Library library = 0;
 
131
FT_Library qt_getFreetype()
 
132
{
 
133
    if (!library)
 
134
        FT_Init_FreeType(&library);
 
135
    return library;
 
136
}
127
137
static QHash<QFontEngine::FaceId, QFreetypeFace *> *freetypeFaces = 0;
128
138
 
129
139
int QFreetypeFace::fsType() const
147
157
 
148
158
    QFreetypeFace *freetype = freetypeFaces->value(face_id, 0);
149
159
    if (!freetype) {
 
160
        freetype = new QFreetypeFace;
150
161
        FT_Face face;
151
 
        if (FT_New_Face(library, face_id.filename, face_id.index, &face))
 
162
        QFile file(QString::fromUtf8(face_id.filename));
 
163
        if (face_id.filename.startsWith(":qmemoryfonts/")) {
 
164
            // from qfontdatabase_x11.cpp
 
165
            extern QByteArray qt_fontdata_from_index(int);
 
166
            QByteArray idx = face_id.filename;
 
167
            idx.remove(0, 14); // remove ':qmemoryfonts/'
 
168
            bool ok = false;
 
169
            freetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
 
170
            if (!ok)
 
171
                freetype->fontData = QByteArray();
 
172
        } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
 
173
            if (!file.open(QIODevice::ReadOnly)) {
 
174
                delete freetype;
 
175
                return 0;
 
176
            }
 
177
            freetype->fontData = file.readAll();
 
178
        }
 
179
        if (!freetype->fontData.isEmpty()) {
 
180
            if (FT_New_Memory_Face(library, (const FT_Byte *)freetype->fontData.constData(), freetype->fontData.size(), face_id.index, &face)) {
 
181
                delete freetype;
 
182
                return 0;
 
183
            }
 
184
        } else if (FT_New_Face(library, face_id.filename, face_id.index, &face)) {
 
185
            delete freetype;
152
186
            return 0;
153
 
        freetype = new QFreetypeFace;
 
187
        }
154
188
        freetype->face = face;
155
189
        freetype->ref = 0;
156
190
        freetype->_lock = 0;
234
268
}
235
269
 
236
270
 
237
 
void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize)
 
271
void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize, bool *outline_drawing)
238
272
{
239
273
    *ysize = fontDef.pixelSize << 6;
240
274
    *xsize = *ysize * fontDef.stretch / 100;
 
275
    *outline_drawing = false;
241
276
 
242
277
    /*
243
278
     * Bitmap only faces must match exactly, so find the closest
260
295
            *ysize = Y_SIZE(face, best);
261
296
        } else
262
297
            *xsize = *ysize = 0;
 
298
    } else {
 
299
        *outline_drawing = (*xsize > (64<<6) || *ysize > (64<<6));
263
300
    }
264
301
}
265
302
 
387
424
    }
388
425
}
389
426
 
 
427
extern void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path);
 
428
 
390
429
static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false)
391
430
{
392
431
    if (slot->format != FT_GLYPH_FORMAT_BITMAP
394
433
        return;
395
434
 
396
435
    QPointF cp = point.toPointF();
397
 
 
398
 
    uchar *src = slot->bitmap.buffer;
399
 
    int h = slot->bitmap.rows;
400
 
    int w = slot->bitmap.width;
401
 
    for (int y = 0; y < h; ++y) {
402
 
        for (int x = 0; x < w; ++x) {
403
 
            uchar pixel = src[x >> 3];
404
 
            if (!pixel) {
405
 
                x += 8;
406
 
                continue;
407
 
            }
408
 
            if (pixel & (0x80 >> (x & 7))) {
409
 
                int rx = x;
410
 
                while (x < w && src[(x+1) >> 3] & (0x80 >> ((x+1) & 7)))
411
 
                    ++x;
412
 
                path->addRect(QRectF(cp.x() + rx + TRUNC(slot->metrics.horiBearingX),
413
 
                                     cp.y() + y - TRUNC(slot->metrics.horiBearingY),
414
 
                                     x - rx + 1, 1));
415
 
            }
416
 
        }
417
 
        src += slot->bitmap.pitch;
418
 
    }
 
436
    qt_addBitmapToPath(cp.x() + TRUNC(slot->metrics.horiBearingX), cp.y() - TRUNC(slot->metrics.horiBearingY),
 
437
                       slot->bitmap.buffer, slot->bitmap.pitch, slot->bitmap.width, slot->bitmap.rows, path);
419
438
}
420
439
 
421
440
#endif // QT_NO_FREETYPE
475
494
        if (((font_path[i])[0] != '/') && !xfsconfig_read) {
476
495
            // We're using xfs -> read its config
477
496
            bool finished = false;
478
 
            QFile f("/etc/X11/fs/config");
479
 
            if (!f.exists())
480
 
                f.setFileName("/usr/X11R6/lib/X11/fs/config");
481
 
            if (!f.exists())
482
 
                f.setFileName("/usr/X11/lib/X11/fs/config");
 
497
            QFile f(QLatin1String("/etc/X11/fs/config"));
 
498
            if (!f.exists())
 
499
                f.setFileName(QLatin1String("/usr/X11R6/lib/X11/fs/config"));
 
500
            if (!f.exists())
 
501
                f.setFileName(QLatin1String("/usr/X11/lib/X11/fs/config"));
483
502
            if (f.exists()) {
484
503
                f.open(QIODevice::ReadOnly);
485
504
                while (f.error()==QFile::NoError && !finished) {
486
 
                    QString fs = f.readLine(1024);
 
505
                    QString fs = QString::fromLocal8Bit(f.readLine(1024));
487
506
                    fs=fs.trimmed();
488
 
                    if (fs.left(9)=="catalogue" && fs.contains('=')) {
489
 
                        fs = fs.mid(fs.indexOf('=') + 1).trimmed();
 
507
                    if (fs.left(9)==QLatin1String("catalogue") && fs.contains(QLatin1Char('='))) {
 
508
                        fs = fs.mid(fs.indexOf(QLatin1Char('=')) + 1).trimmed();
490
509
                        bool end = false;
491
510
                        while (f.error()==QFile::NoError && !end) {
492
 
                            if (fs[int(fs.length())-1] == ',')
 
511
                            if (fs[int(fs.length())-1] == QLatin1Char(','))
493
512
                                fs = fs.left(fs.length()-1);
494
513
                            else
495
514
                                end = true;
496
515
 
497
 
                            fs = fs.left(fs.indexOf(":unscaled"));
498
 
                            if (fs[0] != '#')
 
516
                            fs = fs.left(fs.indexOf(QLatin1String(":unscaled")));
 
517
                            if (fs[0] != QLatin1Char('#'))
499
518
                                fontpath += fs;
500
 
                            fs = f.readLine(1024);
 
519
                            fs = QLatin1String(f.readLine(1024));
501
520
                            fs = fs.trimmed();
502
521
                            if (fs.isEmpty())
503
522
                                end = true;
509
528
            }
510
529
            xfsconfig_read = true;
511
530
        } else {
512
 
            QString fs = QString::fromLatin1(font_path[i]);
513
 
            fontpath += fs.left(fs.indexOf(":unscaled"));
 
531
            QString fs = QString::fromLocal8Bit(font_path[i]);
 
532
            fontpath += fs.left(fs.indexOf(QLatin1String(":unscaled")));
514
533
        }
515
534
    }
516
535
    XFreeFontPath(font_path);
547
566
    QByteArray best_mapping;
548
567
 
549
568
    for (QStringList::ConstIterator it = fontpath.constBegin(); it != fontpath.constEnd(); ++it) {
550
 
        if ((*it).left(1) != "/")
 
569
        if ((*it).left(1) != QLatin1String("/"))
551
570
            continue; // not a path name, a font server
552
571
        QString fontmapname;
553
572
        int num = 0;
554
573
        // search font.dir and font.scale for the right file
555
574
        while (num < 2) {
556
575
            if (num == 0)
557
 
                fontmapname = (*it) + "/fonts.scale";
 
576
                fontmapname = (*it) + QLatin1String("/fonts.scale");
558
577
            else
559
 
                fontmapname = (*it) + "/fonts.dir";
 
578
                fontmapname = (*it) + QLatin1String("/fonts.dir");
560
579
            ++num;
561
580
            //qWarning(fontmapname);
562
581
            QFile fontmap(fontmapname);
573
592
                int index = mapping.indexOf(' ');
574
593
                QByteArray ffn = mapping.mid(0,index);
575
594
                // remove bitmap formats freetype can't handle
576
 
                if(ffn.contains(".spd") || ffn.contains(".phont"))
 
595
                if (ffn.contains(".spd") || ffn.contains(".phont"))
577
596
                    continue;
578
597
                bool best_match = false;
579
598
                if (!best_mapping.isEmpty()) {
706
725
        if (haveNbsp || mirrored) {
707
726
            for (int i = 0; i < len; i++)
708
727
                chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
709
 
                            (mirrored ? ::mirroredChar(str[i]).unicode() : str[i].unicode()));
 
728
                            (mirrored ? QUnicodeTables::mirroredChar(str[i]).unicode() : str[i].unicode()));
710
729
        } else {
711
730
            for (int i = 0; i < len; i++)
712
731
                chars[i] = str[i].unicode();
731
750
        const QChar *c = str + len;
732
751
        if (mirrored) {
733
752
            while (c != str)
734
 
                (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : ::mirroredChar(*c).unicode();
 
753
                (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : QUnicodeTables::mirroredChar(*c).unicode();
735
754
        } else {
736
755
            while (c != str)
737
756
                (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
789
808
    int i;
790
809
 
791
810
    glyph_metrics_t overall;
 
811
    // initialize with line height, we get the same behaviour on all platforms
 
812
    overall.y = -ascent();
 
813
    overall.height = ascent() + descent() + 1;
792
814
    QFixed ymax;
793
815
    QFixed xmax;
794
816
    for (i = 0; i < numGlyphs; i++) {
810
832
            xmax = qMax(xmax, overall.xoff);
811
833
        }
812
834
    }
813
 
    overall.height = ymax - overall.y;
 
835
    overall.height = qMax(overall.height, ymax - overall.y);
814
836
    overall.width = xmax - overall.x;
815
837
 
816
838
    return overall;
953
975
        face_id = ::fontFile(_name, &freetype, &synth);
954
976
        if (_codec)
955
977
            face_id.encoding = _codec->mibEnum();
956
 
        if (freetype)
 
978
        if (freetype) {
957
979
            const_cast<QFontEngineXLFD *>(this)->fsType = freetype->fsType();
 
980
        } else {
 
981
            QFontEngine::Properties properties = QFontEngine::properties();
 
982
            face_id.index = 0;
 
983
            face_id.filename = "-" + properties.postscriptName;
 
984
        }
958
985
    }
959
986
#endif
960
987
 
970
997
    if (freetype)
971
998
        return freetype->properties();
972
999
#endif
973
 
    return Properties();
 
1000
    return QFontEngine::properties();
974
1001
}
975
1002
 
976
 
#ifndef QT_NO_FREETYPE
977
 
 
978
1003
void QFontEngineXLFD::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
979
1004
{
980
1005
    if (face_id.index == -1)
981
1006
        (void)faceId();
 
1007
#ifndef QT_NO_FREETYPE
982
1008
    if (!freetype)
 
1009
#endif
 
1010
    {
 
1011
        QFontEngine::getUnscaledGlyph(glyph, path, metrics);
983
1012
        return;
 
1013
    }
984
1014
 
 
1015
#ifndef QT_NO_FREETYPE
985
1016
    freetype->lock();
986
1017
 
987
1018
    FT_Face face = freetype->face;
1016
1047
    }
1017
1048
    FT_Set_Transform(face, &freetype->matrix, 0);
1018
1049
    freetype->unlock();
 
1050
#endif // QT_NO_FREETYPE
1019
1051
}
1020
1052
 
1021
 
#endif // QT_NO_FREETYPE
1022
1053
 
1023
1054
QByteArray QFontEngineXLFD::getSfntTable(uint tag) const
1024
1055
{
1079
1110
// Multi FT engine
1080
1111
// ------------------------------------------------------------------
1081
1112
 
1082
 
QFontEngineMultiFT::QFontEngineMultiFT(FcFontSet *fs, int s, const QFontDef &request)
1083
 
    : QFontEngineMulti(fs->nfont), fontSet(fs), screen(s)
1084
 
{
1085
 
    fontDef = request;
1086
 
    loadEngine(0);
 
1113
static QFontEngine *engineForPattern(FcPattern *pattern, const QFontDef &request,
 
1114
                                     int screen)
 
1115
{
 
1116
    FcResult res;
 
1117
    FcPattern *match = FcFontMatch(0, pattern, &res);
 
1118
    QFontEngineFT *engine = new QFontEngineFT(match, request, screen);
 
1119
    if (!engine->invalid())
 
1120
        return engine;
 
1121
 
 
1122
    delete engine;
 
1123
    QFontEngine *fe = new QFontEngineBox(request.pixelSize);
 
1124
    fe->fontDef = request;
 
1125
    return fe;
 
1126
}
 
1127
 
 
1128
QFontEngineMultiFT::QFontEngineMultiFT(QFontEngine *fe, FcPattern *p, int s, const QFontDef &req)
 
1129
    : QFontEngineMulti(2), request(req), pattern(p), fontSet(0), screen(s)
 
1130
{
 
1131
 
 
1132
    engines[0] = fe;
 
1133
    engines.at(0)->ref.ref();
1087
1134
    fontDef = engines[0]->fontDef;
1088
1135
    cache_cost = 100;
1089
1136
}
1090
1137
 
1091
1138
QFontEngineMultiFT::~QFontEngineMultiFT()
1092
1139
{
1093
 
    FcFontSetDestroy(fontSet);
 
1140
    FcPatternDestroy(pattern);
 
1141
    if (fontSet)
 
1142
        FcFontSetDestroy(fontSet);
1094
1143
}
1095
1144
 
 
1145
 
1096
1146
void QFontEngineMultiFT::loadEngine(int at)
1097
1147
{
1098
 
    Q_ASSERT(at < engines.size());
1099
 
    Q_ASSERT(engines.at(at) == 0);
1100
 
    FcPattern *pattern = fontSet->fonts[at];
 
1148
    extern void qt_addPatternProps(FcPattern *pattern, int screen, int script,
 
1149
                                   const QFontDef &request);
1101
1150
    extern QFontDef qt_FcPatternToQFontDef(FcPattern *pattern, const QFontDef &);
1102
 
    QFontDef fontDef = qt_FcPatternToQFontDef(fontSet->fonts[at], this->fontDef);
 
1151
    extern FcFontSet *qt_fontSetForPattern(FcPattern *pattern, const QFontDef &request);
 
1152
 
 
1153
    Q_ASSERT(at > 0);
 
1154
    if (!fontSet) {
 
1155
        fontSet = qt_fontSetForPattern(pattern, request);
 
1156
        engines.resize(fontSet->nfont);
 
1157
    }
 
1158
    Q_ASSERT(at < engines.size());
 
1159
    Q_ASSERT(engines.at(at) == 0);
 
1160
 
 
1161
    FcPattern *pattern = FcPatternDuplicate(fontSet->fonts[at]);
 
1162
    qt_addPatternProps(pattern, screen, QUnicodeTables::Common, request);
 
1163
 
 
1164
    QFontDef fontDef = qt_FcPatternToQFontDef(pattern, this->request);
 
1165
 
1103
1166
    // note: we use -1 for the script to make sure that we keep real
1104
1167
    // FT engines separate from Multi engines in the font cache
1105
1168
    QFontCache::Key key(fontDef, -1, screen);
1107
1170
    if (!fontEngine) {
1108
1171
        FcConfigSubstitute(0, pattern, FcMatchPattern);
1109
1172
        FcDefaultSubstitute(pattern);
1110
 
        FcResult res;
1111
 
        FcPattern *match = FcFontMatch(0, pattern, &res);
1112
 
        QFontEngineFT *engine = new QFontEngineFT(match, fontDef, screen);
1113
 
        if (engine->invalid())
1114
 
            delete engine;
1115
 
        else
1116
 
            fontEngine = engine;
1117
 
        if (!fontEngine) {
1118
 
            fontEngine = new QFontEngineBox(fontDef.pixelSize);
1119
 
            fontEngine->fontDef = fontDef;
1120
 
        }
 
1173
        fontEngine = engineForPattern(pattern, request, screen);
 
1174
        FcPatternDestroy(pattern);
1121
1175
        QFontCache::instance->insertEngine(key, fontEngine);
1122
1176
    }
1123
1177
    fontEngine->ref.ref();
1149
1203
 
1150
1204
QFontEngineFT::QFontEngineFT(FcPattern *pattern, const QFontDef &fd, int screen)
1151
1205
{
 
1206
    _openType = 0;
1152
1207
    cache_cost = 100;
1153
1208
    fontDef = fd;
1154
1209
    _pattern = pattern;
1182
1237
    face_id = ::face_id(pattern);
1183
1238
 
1184
1239
    freetype = QFreetypeFace::getFace(face_id);
 
1240
    if (!freetype) {
 
1241
        xsize = 0;
 
1242
        ysize = 0;
 
1243
        return;
 
1244
    }
 
1245
 
1185
1246
    if (!freetype->charset) {
1186
1247
        FcCharSet *cs;
1187
1248
        FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
1188
1249
        freetype->charset = FcCharSetCopy(cs);
1189
1250
    }
 
1251
    symbol = freetype->symbol_map != 0;
1190
1252
 
1191
1253
    lbearing = rbearing = SHRT_MIN;
1192
 
    freetype->computeSize(fontDef, &xsize, &ysize);
1193
 
    outline_drawing = xsize > (64<<6) || ysize > (64<<6);
 
1254
    freetype->computeSize(fontDef, &xsize, &ysize, &outline_drawing);
1194
1255
 
1195
1256
    FT_Face face = lockFace();
1196
1257
 
1233
1294
                 || subpixel == FC_RGBA_VRGB
1234
1295
                 || subpixel == FC_RGBA_VBGR)
1235
1296
            format = PictStandardARGB32;
1236
 
        glyphSet = XRenderCreateGlyphSet(X11->display,
1237
 
                                         XRenderFindStandardFormat(X11->display, format));
 
1297
        fnt.glyphSet = XRenderCreateGlyphSet(X11->display,
 
1298
                                             XRenderFindStandardFormat(X11->display, format));
1238
1299
        xglyph_format = format;
1239
1300
    } else {
1240
 
        glyphSet = 0;
 
1301
        fnt.glyphSet = 0;
1241
1302
    }
1242
1303
#endif
1243
 
 
1244
 
    _openType = 0;
1245
1304
}
1246
1305
 
1247
1306
QFontEngineFT::~QFontEngineFT()
1249
1308
    delete _openType;
1250
1309
    _openType = 0;
1251
1310
 
 
1311
    if (freetype)
1252
1312
    freetype->release(face_id);
1253
1313
 
1254
1314
    FcPatternDestroy(_pattern);
1255
1315
    _pattern = 0;
1256
 
 
1257
 
    qDeleteAll(glyph_data);
1258
 
#ifndef QT_NO_XRENDER
1259
 
    if (glyphSet)
1260
 
        XRenderFreeGlyphSet(X11->display, glyphSet);
1261
 
#endif
1262
1316
}
1263
1317
 
1264
1318
FT_Face QFontEngineFT::lockFace() const
1297
1351
    { 16, 60, 180 }
1298
1352
};
1299
1353
 
1300
 
 
1301
 
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(uint glyph, GlyphFormat format) const
 
1354
QFontEngineFT::Font::Font()
 
1355
#ifndef QT_NO_XRENDER
 
1356
    : glyphSet(0)
 
1357
#endif
 
1358
{
 
1359
    transformationMatrix.xx = 0x10000;
 
1360
    transformationMatrix.yy = 0x10000;
 
1361
    transformationMatrix.xy = 0;
 
1362
    transformationMatrix.yx = 0;
 
1363
}
 
1364
 
 
1365
QFontEngineFT::Font::~Font()
 
1366
{
 
1367
    qDeleteAll(glyph_data);
 
1368
#ifndef QT_NO_XRENDER
 
1369
    if (glyphSet != 0)
 
1370
        XRenderFreeGlyphSet(X11->display, glyphSet);
 
1371
#endif
 
1372
}
 
1373
 
 
1374
QFontEngineFT::Glyph *QFontEngineFT::Font::loadGlyph(const QFontEngineFT *fe, uint glyph, GlyphFormat format) const
1302
1375
{
1303
1376
//     Q_ASSERT(freetype->lock == 1);
1304
1377
 
1307
1380
        format = Format_Mono;
1308
1381
        if (X11->use_xrender) {
1309
1382
            add_to_glyphset = true;
1310
 
            if (subpixel != FC_RGBA_NONE)
 
1383
            if (fe->subpixel != FC_RGBA_NONE)
1311
1384
                format = Format_A32;
1312
 
            else if (antialias)
 
1385
            else if (fe->antialias)
1313
1386
                format = Format_A8;
1314
1387
        }
1315
1388
    }
1316
1389
    Q_ASSERT(format != Format_None);
1317
 
    int hfactor = 1;
 
1390
    bool hsubpixel = false;
1318
1391
    int vfactor = 1;
1319
1392
    int load_flags = FT_LOAD_DEFAULT;
1320
 
    if (outline_drawing) {
 
1393
    if (fe->outline_drawing) {
1321
1394
        load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
1322
1395
    } else if (format == Format_Mono) {
1323
1396
        load_flags |= FT_LOAD_TARGET_MONO;
1324
1397
    } else if (format == Format_A32) {
1325
 
        if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
 
1398
        if (fe->subpixel == FC_RGBA_RGB || fe->subpixel == FC_RGBA_BGR) {
1326
1399
            load_flags |= FT_LOAD_TARGET_LCD;
1327
 
            hfactor = 3;
1328
 
        } else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
 
1400
            hsubpixel = true;
 
1401
        } else if (fe->subpixel == FC_RGBA_VRGB || fe->subpixel == FC_RGBA_VBGR) {
1329
1402
            load_flags |= FT_LOAD_TARGET_LCD_V;
1330
1403
            vfactor = 3;
1331
1404
        }
1335
1408
        load_flags |= FT_LOAD_NO_BITMAP;
1336
1409
 
1337
1410
#ifdef FC_HINT_STYLE
1338
 
    if (hint_style == FC_HINT_NONE)
 
1411
    if (fe->hint_style == FC_HINT_NONE)
1339
1412
        load_flags |= FT_LOAD_NO_HINTING;
1340
 
    else if (hint_style < FC_HINT_FULL)
 
1413
    else if (fe->hint_style < FC_HINT_FULL)
1341
1414
        load_flags |= FT_LOAD_TARGET_LIGHT;
1342
1415
#endif
1343
1416
 
1344
1417
#ifdef FT_LOAD_FORCE_AUTOHINT
1345
 
    if (autohint)
 
1418
    if (fe->autohint)
1346
1419
        load_flags |= FT_LOAD_FORCE_AUTOHINT;
1347
1420
#endif
1348
1421
 
 
1422
    bool transform = fe->transform
 
1423
                     || transformationMatrix.xx != 0x10000
 
1424
                     || transformationMatrix.yy != 0x10000
 
1425
                     || transformationMatrix.xy != 0
 
1426
                     || transformationMatrix.yx != 0;
 
1427
 
1349
1428
    if (transform)
1350
1429
        load_flags |= FT_LOAD_NO_BITMAP;
1351
1430
 
1355
1434
            return g;
1356
1435
    }
1357
1436
 
 
1437
    const QFreetypeFace * const freetype = fe->freetype;
1358
1438
    FT_Face face = freetype->face;
1359
1439
    FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
1360
1440
    if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
1369
1449
    if (err != FT_Err_Ok)
1370
1450
        qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
1371
1451
 
1372
 
    if (outline_drawing)
 
1452
    if (fe->outline_drawing)
1373
1453
        return 0;
1374
1454
 
1375
1455
    FT_GlyphSlot slot = face->glyph;
1376
1456
 
 
1457
    FT_Matrix matrix = freetype->matrix;
 
1458
 
1377
1459
    int left  = slot->metrics.horiBearingX;
1378
1460
    int right = slot->metrics.horiBearingX + slot->metrics.width;
1379
1461
    int top    = slot->metrics.horiBearingY;
1417
1499
    bottom = FLOOR(bottom);
1418
1500
    top = CEIL(top);
1419
1501
 
 
1502
    int hpixels = TRUNC(right - left);
 
1503
    if (hsubpixel)
 
1504
        hpixels = hpixels*3 + 8;
1420
1505
#ifndef QT_NO_XRENDER
1421
1506
    XGlyphInfo info;
1422
1507
#else
1430
1515
    } XGlyphInfoDummy;
1431
1516
    XGlyphInfoDummy info;
1432
1517
#endif
1433
 
    info.width = TRUNC(right - left);
 
1518
    info.width = hpixels;
1434
1519
    info.height = TRUNC(top - bottom);
1435
1520
    info.x = -TRUNC(left);
1436
1521
    info.y = TRUNC(top);
1437
1522
    info.xOff = TRUNC(ROUND(slot->advance.x));
1438
1523
    info.yOff = 0;
 
1524
    if (hsubpixel) {
 
1525
        info.width /= 3;
 
1526
        info.x += 1;
 
1527
    }
1439
1528
 
1440
1529
    int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
1441
1530
                 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
1442
 
    int size = pitch * info.height * vfactor;
1443
 
    uchar *buffer = new uchar[size];
1444
 
    memset (buffer, 0, size);
 
1531
    int size = pitch * info.height;
 
1532
    uchar *glyph_buffer = new uchar[size];
1445
1533
 
1446
1534
    if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
1447
1535
        FT_Bitmap bitmap;
1448
1536
        bitmap.rows = info.height*vfactor;
1449
 
        bitmap.width = info.width*hfactor;
1450
 
        bitmap.pitch = pitch;
1451
 
        bitmap.buffer = buffer;
 
1537
        bitmap.width = hpixels;
 
1538
        bitmap.pitch = format == Format_Mono ? (((info.width + 31) & ~31) >> 3) : ((bitmap.width + 3) & ~3);
 
1539
        if (!hsubpixel && vfactor == 1)
 
1540
            bitmap.buffer = glyph_buffer;
 
1541
        else
 
1542
            bitmap.buffer = new uchar[bitmap.rows*bitmap.pitch];
 
1543
        memset(bitmap.buffer, 0, bitmap.rows*bitmap.pitch);
1452
1544
        bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
1453
1545
        FT_Matrix matrix;
1454
 
        matrix.xx = hfactor << 16;
 
1546
        matrix.xx = (hsubpixel ? 3 : 1) << 16;
1455
1547
        matrix.yy = vfactor << 16;
1456
1548
        matrix.yx = matrix.xy = 0;
1457
1549
 
1458
1550
        FT_Outline_Transform(&slot->outline, &matrix);
1459
 
        FT_Outline_Translate (&slot->outline, -left*hfactor, -bottom*vfactor);
 
1551
        FT_Outline_Translate (&slot->outline, (hsubpixel ? -3*left +(4<<6) : -left), -bottom*vfactor);
1460
1552
        FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
1461
 
        if (hfactor != 1) {
 
1553
        if (hsubpixel) {
1462
1554
            Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
1463
 
            Q_ASSERT(antialias);
1464
 
            uchar *src = buffer;
1465
 
            size = info.width * 4 * info.height;
1466
 
            uchar *newBuf = new uchar[size];
1467
 
            uint *dst = (uint *)newBuf;
 
1555
            Q_ASSERT(fe->antialias);
 
1556
            const uchar *src = bitmap.buffer;
 
1557
            uchar *convoluted = new uchar[bitmap.rows*bitmap.pitch];
 
1558
            uchar *c = convoluted;
 
1559
            // convolute the bitmap with a triangle filter to get rid of color fringes
 
1560
            // If we take account for a gamma value of 2, we end up with
 
1561
            // weights of 1, 4, 9, 4, 1. We use an approximation of 1, 3, 8, 3, 1 here,
 
1562
            // as this nicely sums up to 16 :)
1468
1563
            int h = info.height;
1469
 
            if (subpixel == FC_RGBA_RGB) {
 
1564
            while (h--) {
 
1565
                c[0] = c[1] = 0;
 
1566
                //
 
1567
                for (int x = 2; x < bitmap.width - 2; ++x) {
 
1568
                    uint sum = src[x-2] + 3*src[x-1] + 8*src[x] + 3*src[x+1] + src[x+2];
 
1569
                    c[x] = (uchar) (sum >> 4);
 
1570
                }
 
1571
                c[bitmap.width - 2] = c[bitmap.width -1] = 0;
 
1572
                src += bitmap.pitch;
 
1573
                c += bitmap.pitch;
 
1574
            }
 
1575
 
 
1576
            uint *dst = (uint *)glyph_buffer;
 
1577
            src = convoluted;
 
1578
            h = info.height;
 
1579
            if (fe->subpixel == FC_RGBA_RGB) {
1470
1580
                while (h--) {
1471
1581
                    uint *dd = dst;
1472
 
                    for (int x = 0; x < bitmap.width; x += 3) {
 
1582
                    for (int x = 1; x < bitmap.width - 1; x += 3) {
1473
1583
                        uint red = src[x];
1474
1584
                        uint green = src[x+1];
1475
1585
                        uint blue = src[x+2];
1476
 
                        uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
1477
 
                        uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
1478
 
                        uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
1479
 
                        uint res = (high << 16) + (mid << 8) + low;
 
1586
                        uint res = (red << 16) + (green << 8) + blue;
1480
1587
                        *dd = res;
1481
1588
                        ++dd;
1482
1589
                    }
1486
1593
            } else {
1487
1594
                while (h--) {
1488
1595
                    uint *dd = dst;
1489
 
                    for (int x = 0; x < bitmap.width; x += 3) {
 
1596
                    for (int x = 1; x < bitmap.width - 1; x += 3) {
1490
1597
                        uint blue = src[x];
1491
1598
                        uint green = src[x+1];
1492
1599
                        uint red = src[x+2];
1493
 
                        uint high = (red*subpixel_filter[0][0] + green*subpixel_filter[0][1] + blue*subpixel_filter[0][2]) >> 8;
1494
 
                        uint mid = (red*subpixel_filter[1][0] + green*subpixel_filter[1][1] + blue*subpixel_filter[1][2]) >> 8;
1495
 
                        uint low = (red*subpixel_filter[2][0] + green*subpixel_filter[2][1] + blue*subpixel_filter[2][2]) >> 8;
1496
 
                        uint res = (high << 16) + (mid << 8) + low;
 
1600
                        uint res = (red << 16) + (green << 8) + blue;
1497
1601
                        *dd = res;
1498
1602
                        ++dd;
1499
1603
                    }
1501
1605
                    src += bitmap.pitch;
1502
1606
                }
1503
1607
            }
1504
 
            delete [] buffer;
1505
 
            buffer = newBuf;
 
1608
            delete [] convoluted;
 
1609
            delete [] bitmap.buffer;
1506
1610
        } else if (vfactor != 1) {
1507
 
            uchar *src = buffer;
 
1611
            uchar *src = bitmap.buffer;
1508
1612
            size = info.width * 4 * info.height;
1509
 
            uchar *newBuf = new uchar[size];
1510
 
            uint *dst = (uint *)newBuf;
 
1613
            uint *dst = (uint *)glyph_buffer;
1511
1614
            int h = info.height;
1512
 
            if (subpixel == FC_RGBA_VRGB) {
 
1615
            if (fe->subpixel == FC_RGBA_VRGB) {
1513
1616
                while (h--) {
1514
1617
                    for (int x = 0; x < info.width; x++) {
1515
1618
                        uint red = src[x];
1540
1643
                    src += 3*bitmap.pitch;
1541
1644
                }
1542
1645
            }
1543
 
            delete [] buffer;
1544
 
            buffer = newBuf;
 
1646
            delete [] bitmap.buffer;
1545
1647
        }
1546
1648
    } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
1547
1649
        Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
1548
1650
        uchar *src = slot->bitmap.buffer;
1549
 
        uchar *dst = buffer;
 
1651
        uchar *dst = glyph_buffer;
1550
1652
        int h = slot->bitmap.rows;
1551
1653
        if (format == Format_Mono) {
1552
1654
            int bytes = ((info.width + 7) & ~7) >> 3;
1556
1658
                src += slot->bitmap.pitch;
1557
1659
            }
1558
1660
        } else {
1559
 
            if (hfactor != 1 || vfactor != 1) {
1560
 
                while (h--) {
1561
 
                    uint *dd = (uint *)dst;
1562
 
                    for (int x = 0; x < slot->bitmap.width; x++) {
1563
 
                        unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
1564
 
                        *dd++ = (a << 16) | (a << 8) | a;
 
1661
            if (hsubpixel) {
 
1662
                while (h--) {
 
1663
                    uint *dd = (uint *)dst;
 
1664
                    *dd++ = 0;
 
1665
                    for (int x = 0; x < slot->bitmap.width; x++) {
 
1666
                        uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
 
1667
                        *dd++ = a;
 
1668
                    }
 
1669
                    *dd++ = 0;
 
1670
                    dst += pitch;
 
1671
                    src += slot->bitmap.pitch;
 
1672
                }
 
1673
            } else if (vfactor != 1) {
 
1674
                while (h--) {
 
1675
                    uint *dd = (uint *)dst;
 
1676
                    for (int x = 0; x < slot->bitmap.width; x++) {
 
1677
                        uint a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xffffff : 0x000000);
 
1678
                        *dd++ = a;
1565
1679
                    }
1566
1680
                    dst += pitch;
1567
1681
                    src += slot->bitmap.pitch;
1578
1692
            }
1579
1693
        }
1580
1694
    } else {
1581
 
        qWarning("glyph neither outline nor bitmap format=%d", slot->format);
1582
 
        delete [] buffer;
 
1695
        qWarning("QFontEngine: Glyph neither outline nor bitmap format=%d", slot->format);
 
1696
        delete [] glyph_buffer;
1583
1697
        return 0;
1584
1698
    }
1585
1699
 
1590
1704
             * swap bit order around; FreeType is always MSBFirst
1591
1705
             */
1592
1706
            if (BitmapBitOrder(X11->display) != MSBFirst) {
1593
 
                unsigned char *line = (unsigned char *) buffer;
 
1707
                unsigned char *line = (unsigned char *) glyph_buffer;
1594
1708
                int i = size;
1595
1709
                i = size;
1596
1710
                while (i--) {
1605
1719
        }
1606
1720
 
1607
1721
        ::Glyph xglyph = glyph;
1608
 
        XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)buffer, size);
1609
 
        delete [] buffer;
1610
 
        buffer = 0;
 
1722
        XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)glyph_buffer, size);
 
1723
        delete [] glyph_buffer;
 
1724
        glyph_buffer = 0;
1611
1725
    }
1612
1726
#endif
1613
1727
 
1627
1741
    Glyph *g = new Glyph;
1628
1742
 
1629
1743
    g->linearAdvance = slot->linearHoriAdvance >> 10;
1630
 
    g->width = TRUNC(right - left);
 
1744
    g->width = info.width;
1631
1745
    g->height = TRUNC(top - bottom);
1632
 
    g->x = TRUNC(left);
 
1746
    g->x = -info.x;
1633
1747
    g->y = TRUNC(top);
1634
1748
    g->advance = TRUNC(ROUND(slot->advance.x));
1635
1749
    g->format = add_to_glyphset ? Format_None : format;
1636
 
    g->data = buffer;
 
1750
    g->data = glyph_buffer;
1637
1751
 
1638
1752
    // make sure we delete the old cached glyph
1639
1753
    delete glyph_data.value(glyph);
1641
1755
 
1642
1756
    return g;
1643
1757
}
 
1758
#ifndef QT_NO_XRENDER
 
1759
bool QFontEngineFT::loadTransformedGlyphSet(glyph_t *glyphs, int num_glyphs, const QMatrix &matrix, GlyphSet *gs)
 
1760
{
 
1761
    // don't try to load huge fonts
 
1762
    if (fontDef.pixelSize * sqrt(matrix.det()) >= 64) {
 
1763
        *gs = 0;
 
1764
        return false;
 
1765
    }
 
1766
 
 
1767
    FT_Matrix m;
 
1768
    m.xx = FT_Fixed(matrix.m11() * 65536);
 
1769
    m.xy = FT_Fixed(-matrix.m21() * 65536);
 
1770
    m.yx = FT_Fixed(-matrix.m12() * 65536);
 
1771
    m.yy = FT_Fixed(matrix.m22() * 65536);
 
1772
 
 
1773
    Font *font = 0;
 
1774
 
 
1775
    for (int i = 0; i < transformedFonts.count(); ++i) {
 
1776
        const Font &f = transformedFonts.at(i);
 
1777
        if (f.transformationMatrix.xx == m.xx
 
1778
            && f.transformationMatrix.xy == m.xy
 
1779
            && f.transformationMatrix.yx == m.yx
 
1780
            && f.transformationMatrix.yy == m.yy) {
 
1781
 
 
1782
            // found a match, move it to the front
 
1783
            transformedFonts.move(i, 0);
 
1784
            font = &transformedFonts[0];
 
1785
            break;
 
1786
        }
 
1787
    }
 
1788
 
 
1789
    if (!font) {
 
1790
        // don't cache more than 10 transformations
 
1791
        if (transformedFonts.count() >= 10) {
 
1792
            transformedFonts.move(transformedFonts.size() - 1, 0);
 
1793
            XRenderFreeGlyphSet(X11->display, transformedFonts.at(0).glyphSet);
 
1794
        } else {
 
1795
            transformedFonts.prepend(Font());
 
1796
        }
 
1797
        font = &transformedFonts[0];
 
1798
 
 
1799
        qDeleteAll(font->glyph_data);
 
1800
        font->glyph_data.clear();
 
1801
 
 
1802
        font->glyphSet = XRenderCreateGlyphSet(X11->display,
 
1803
                         XRenderFindStandardFormat(X11->display, xglyph_format));
 
1804
 
 
1805
        font->transformationMatrix = m;
 
1806
    }
 
1807
 
 
1808
    FT_Face face = 0;
 
1809
    bool lockedFace = false;
 
1810
 
 
1811
    for (int i = 0; i < num_glyphs; ++i) {
 
1812
        if (!font->glyph_data.contains(glyphs[i])) {
 
1813
            if (!lockedFace) {
 
1814
                face = lockFace();
 
1815
                m = this->matrix;
 
1816
                FT_Matrix_Multiply(&font->transformationMatrix, &m);
 
1817
                FT_Set_Transform(face, &m, 0);
 
1818
                freetype->matrix = m;
 
1819
                lockedFace = true;
 
1820
            }
 
1821
            if (!font->loadGlyph(this, glyphs[i])) {
 
1822
                FT_Set_Transform(face, &freetype->matrix, 0);
 
1823
                unlockFace();
 
1824
                return false;
 
1825
            }
 
1826
        }
 
1827
    }
 
1828
    *gs = font->glyphSet;
 
1829
 
 
1830
    if (lockedFace) {
 
1831
        FT_Set_Transform(face, &freetype->matrix, 0);
 
1832
        unlockFace();
 
1833
    }
 
1834
 
 
1835
    return true;
 
1836
}
 
1837
#endif
1644
1838
 
1645
1839
inline unsigned int getChar(const QChar *str, int &i, const int len)
1646
1840
{
1725
1919
    FT_Face face = 0;
1726
1920
    if (flags & QTextEngine::DesignMetrics) {
1727
1921
        for (int i = 0; i < len; i++) {
1728
 
            Glyph *g = glyph_data.value(glyphs[i].glyph);
 
1922
            Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
1729
1923
            if (!g) {
1730
1924
                if (!face)
1731
1925
                    face = lockFace();
1737
1931
        }
1738
1932
    } else {
1739
1933
        for (int i = 0; i < len; i++) {
1740
 
            Glyph *g = glyph_data.value(glyphs[i].glyph);
 
1934
            Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
1741
1935
            if (!g) {
1742
1936
                if (!face)
1743
1937
                    face = lockFace();
1758
1952
    FT_Face face = 0;
1759
1953
 
1760
1954
    glyph_metrics_t overall;
 
1955
    // initialize with line height, we get the same behaviour on all platforms
 
1956
    overall.y = -ascent();
 
1957
    overall.height = ascent() + descent() + 1;
 
1958
 
1761
1959
    QFixed ymax = 0;
1762
1960
    QFixed xmax = 0;
1763
1961
    for (int i = 0; i < numGlyphs; i++) {
1764
 
        Glyph *g = glyph_data.value(glyphs[i].glyph);
 
1962
        Glyph *g = fnt.glyph_data.value(glyphs[i].glyph);
1765
1963
        if (!g) {
1766
1964
            if (!face)
1767
1965
                face = lockFace();
1790
1988
            overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
1791
1989
        }
1792
1990
    }
1793
 
    overall.height = ymax - overall.y;
 
1991
    overall.height = qMax(overall.height, ymax - overall.y);
1794
1992
    overall.width = xmax - overall.x;
1795
1993
 
1796
1994
    if (face)
1803
2001
{
1804
2002
    FT_Face face = 0;
1805
2003
    glyph_metrics_t overall;
1806
 
    Glyph *g = glyph_data.value(glyph);
 
2004
    Glyph *g = fnt.glyph_data.value(glyph);
1807
2005
    if (!g) {
1808
2006
        face = lockFace();
1809
2007
        g = loadGlyph(glyph);
1900
2098
    }
1901
2099
}
1902
2100
 
 
2101
QImage QFontEngineFT::alphaMapForGlyph(glyph_t g)
 
2102
{
 
2103
    lockFace();
 
2104
 
 
2105
    Glyph *glyph = loadGlyph(g, Format_A8);
 
2106
    if (!glyph) {
 
2107
        unlockFace();
 
2108
        return QFontEngine::alphaMapForGlyph(g);
 
2109
    }
 
2110
 
 
2111
    Q_ASSERT(glyph->format == QFontEngineFT::Format_A8);
 
2112
 
 
2113
    const int pitch = (glyph->width + 3) & ~3;
 
2114
 
 
2115
    QImage img(glyph->width, glyph->height, QImage::Format_Indexed8);
 
2116
    QVector<QRgb> colors(256);
 
2117
    for (int i=0; i<256; ++i)
 
2118
        colors[i] = qRgba(0, 0, 0, i);
 
2119
    img.setColorTable(colors);
 
2120
 
 
2121
    for (int y = 0; y < glyph->height; ++y)
 
2122
        memcpy(img.scanLine(y), &glyph->data[y * pitch], glyph->width);
 
2123
    unlockFace();
 
2124
 
 
2125
    return img;
 
2126
}
 
2127
 
1903
2128
QFixed QFontEngineFT::ascent() const
1904
2129
{
1905
2130
    return QFixed::fromFixed(metrics.ascender);
1917
2142
 
1918
2143
QFixed QFontEngineFT::xHeight() const
1919
2144
{
1920
 
    TT_PCLT *pct = (TT_PCLT *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_pclt);
1921
 
    if (pct && pct->xHeight) {
1922
 
        return QFixed(pct->xHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1923
 
    }
 
2145
    TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
 
2146
    if (os2 && os2->sxHeight)
 
2147
        return QFixed(os2->sxHeight*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
1924
2148
    return QFontEngine::xHeight();
1925
2149
}
1926
2150
 
 
2151
QFixed QFontEngineFT::averageCharWidth() const
 
2152
{
 
2153
    TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2);
 
2154
    if (os2 && os2->xAvgCharWidth)
 
2155
        return QFixed(os2->xAvgCharWidth*freetype->face->size->metrics.y_ppem)/freetype->face->units_per_EM;
 
2156
    return QFontEngine::averageCharWidth();
 
2157
}
 
2158
 
1927
2159
 
1928
2160
qreal QFontEngineFT::maxCharWidth() const
1929
2161
{
2000
2232
    Properties p = freetype->properties();
2001
2233
    if (p.postscriptName.isEmpty()) {
2002
2234
        p.postscriptName = fontDef.family.toUtf8();
2003
 
        p.postscriptName.replace(" ", "");
 
2235
        p.postscriptName = QPdf::stripSpecialCharacters(p.postscriptName);
2004
2236
    }
2005
2237
 
2006
2238
    return freetype->properties();