~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): Adam Conrad
  • Date: 2005-08-24 04:09:09 UTC
  • Revision ID: james.westby@ubuntu.com-20050824040909-xmxe9jfr4a0w5671
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 1992-2005 Trolltech AS. All rights reserved.
 
4
**
 
5
** This file is part of the text module of the Qt Toolkit.
 
6
**
 
7
** This file may be distributed under the terms of the Q Public License
 
8
** as defined by Trolltech AS of Norway and appearing in the file
 
9
** LICENSE.QPL included in the packaging of this file.
 
10
**
 
11
** This file may be distributed and/or modified under the terms of the
 
12
** GNU General Public License version 2 as published by the Free Software
 
13
** Foundation and appearing in the file LICENSE.GPL included in the
 
14
** packaging of this file.
 
15
**
 
16
** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
 
17
**   information about Qt Commercial License Agreements.
 
18
** See http://www.trolltech.com/qpl/ for QPL licensing information.
 
19
** See http://www.trolltech.com/gpl/ for GPL licensing information.
 
20
**
 
21
** Contact info@trolltech.com if any conditions of this licensing are
 
22
** not clear to you.
 
23
**
 
24
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 
25
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
26
**
 
27
****************************************************************************/
 
28
 
 
29
#include "qbitmap.h"
 
30
 
 
31
// #define FONTENGINE_DEBUG
 
32
 
 
33
#include <qbytearray.h>
 
34
#include <qtextcodec.h>
 
35
 
 
36
#include "qfontdatabase.h"
 
37
#include "qpaintdevice.h"
 
38
#include "qpainter.h"
 
39
#include "qvarlengtharray.h"
 
40
#include "qwidget.h"
 
41
 
 
42
#include <private/qpaintengine_x11_p.h>
 
43
#include "qfont.h"
 
44
#include "qfont_p.h"
 
45
#include "qfontengine_p.h"
 
46
#include "qopentype_p.h"
 
47
#include <qhash.h>
 
48
 
 
49
#include <private/qpainter_p.h>
 
50
#include <private/qunicodetables_p.h>
 
51
 
 
52
#include <private/qt_x11_p.h>
 
53
 
 
54
#include <qdebug.h>
 
55
 
 
56
#include <math.h>
 
57
#include <limits.h>
 
58
 
 
59
QFontEngine::~QFontEngine()
 
60
{
 
61
}
 
62
 
 
63
qreal QFontEngine::lineThickness() const
 
64
{
 
65
    // ad hoc algorithm
 
66
    int score = fontDef.weight * fontDef.pixelSize;
 
67
    int lw = score / 700;
 
68
 
 
69
    // looks better with thicker line for small pointsizes
 
70
    if (lw < 2 && score >= 1050) lw = 2;
 
71
    if (lw == 0) lw = 1;
 
72
 
 
73
    return lw;
 
74
}
 
75
 
 
76
qreal QFontEngine::underlinePosition() const
 
77
{
 
78
    return ((lineThickness() * 2) + 3) / 6;
 
79
}
 
80
 
 
81
 
 
82
// ------------------------------------------------------------------
 
83
// Multi XLFD engine
 
84
// ------------------------------------------------------------------
 
85
 
 
86
QFontEngineMultiXLFD::QFontEngineMultiXLFD(const QFontDef &r, const QList<int> &l, int s)
 
87
    : QFontEngineMulti(l.size()), encodings(l), screen(s)
 
88
{
 
89
    fontDef = r;
 
90
    loadEngine(0);
 
91
}
 
92
 
 
93
QFontEngineMultiXLFD::~QFontEngineMultiXLFD()
 
94
{ }
 
95
 
 
96
void QFontEngineMultiXLFD::loadEngine(int at)
 
97
{
 
98
    Q_ASSERT(at < engines.size());
 
99
    Q_ASSERT(engines.at(at) == 0);
 
100
    const int encoding = encodings.at(at);
 
101
    QFontDef req = fontDef;
 
102
    QFontEngine *fontEngine = QFontDatabase::findFont(QUnicodeTables::Common, 0, req, encoding);
 
103
    if (!fontEngine) {
 
104
        req.family.clear();
 
105
        fontEngine = QFontDatabase::findFont(QUnicodeTables::Common, 0, req, encoding);
 
106
    }
 
107
    Q_ASSERT(fontEngine != 0);
 
108
    fontEngine->ref.ref();
 
109
    engines[at] = fontEngine;
 
110
}
 
111
 
 
112
// ------------------------------------------------------------------
 
113
// Xlfd cont engine
 
114
// ------------------------------------------------------------------
 
115
 
 
116
// defined in qfontdatbase_x11.cpp
 
117
extern int qt_mib_for_xlfd_encoding(const char *encoding);
 
118
extern int qt_xlfd_encoding_id(const char *encoding);
 
119
 
 
120
static inline XCharStruct *charStruct(XFontStruct *xfs, uint ch)
 
121
{
 
122
    XCharStruct *xcs = 0;
 
123
    unsigned char r = ch>>8;
 
124
    unsigned char c = ch&0xff;
 
125
    if (r >= xfs->min_byte1 &&
 
126
         r <= xfs->max_byte1 &&
 
127
         c >= xfs->min_char_or_byte2 &&
 
128
         c <= xfs->max_char_or_byte2) {
 
129
        if (!xfs->per_char)
 
130
            xcs = &(xfs->min_bounds);
 
131
        else {
 
132
            xcs = xfs->per_char + ((r - xfs->min_byte1) *
 
133
                                   (xfs->max_char_or_byte2 -
 
134
                                    xfs->min_char_or_byte2 + 1)) +
 
135
                  (c - xfs->min_char_or_byte2);
 
136
            if (xcs->width == 0 && xcs->ascent == 0 &&  xcs->descent == 0)
 
137
                xcs = 0;
 
138
        }
 
139
    }
 
140
    return xcs;
 
141
}
 
142
 
 
143
QFontEngineXLFD::QFontEngineXLFD(XFontStruct *fs, const char *name, int mib)
 
144
    : _fs(fs), _name(name), _codec(0), _cmap(mib)
 
145
{
 
146
    if (_cmap) _codec = QTextCodec::codecForMib(_cmap);
 
147
 
 
148
    cache_cost = (((fs->max_byte1 - fs->min_byte1) *
 
149
                   (fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1)) +
 
150
                  fs->max_char_or_byte2 - fs->min_char_or_byte2);
 
151
    cache_cost = ((fs->max_bounds.ascent + fs->max_bounds.descent) *
 
152
                  (fs->max_bounds.width * cache_cost / 8));
 
153
    lbearing = SHRT_MIN;
 
154
    rbearing = SHRT_MIN;
 
155
}
 
156
 
 
157
QFontEngineXLFD::~QFontEngineXLFD()
 
158
{
 
159
    XFreeFont(QX11Info::display(), _fs);
 
160
    _fs = 0;
 
161
}
 
162
 
 
163
QFontEngine::FECaps QFontEngineXLFD::capabilites() const
 
164
{
 
165
    return FullTransformations;
 
166
}
 
167
 
 
168
bool QFontEngineXLFD::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
 
169
{
 
170
    if (*nglyphs < len) {
 
171
        *nglyphs = len;
 
172
        return false;
 
173
    }
 
174
 
 
175
    bool mirrored = flags & QTextEngine::RightToLeft;
 
176
    if (_codec) {
 
177
        bool haveNbsp = false;
 
178
        for (int i = 0; i < len; i++)
 
179
            if (str[i].unicode() == 0xa0) {
 
180
                haveNbsp = true;
 
181
                break;
 
182
            }
 
183
 
 
184
        QVarLengthArray<unsigned short> ch(len);
 
185
        QChar *chars = (QChar *)ch.data();
 
186
        if (haveNbsp || mirrored) {
 
187
            for (int i = 0; i < len; i++)
 
188
                chars[i] = (str[i].unicode() == 0xa0 ? 0x20 :
 
189
                            (mirrored ? ::mirroredChar(str[i]).unicode() : str[i].unicode()));
 
190
        } else {
 
191
            for (int i = 0; i < len; i++)
 
192
                chars[i] = str[i].unicode();
 
193
        }
 
194
        QTextCodec::ConverterState state;
 
195
        state.flags = QTextCodec::ConvertInvalidToNull;
 
196
        QByteArray ba = _codec->fromUnicode(chars, len, &state);
 
197
        if (ba.length() == 2*len) {
 
198
            // double byte encoding
 
199
            const uchar *data = (const uchar *)ba.constData();
 
200
            for (int i = 0; i < len; i++) {
 
201
                glyphs[i].glyph = ((ushort)data[0] << 8) + data[1];
 
202
                data += 2;
 
203
            }
 
204
        } else {
 
205
            const uchar *data = (const uchar *)ba.constData();
 
206
            for (int i = 0; i < len; i++)
 
207
                glyphs[i].glyph = (ushort)data[i];
 
208
        }
 
209
    } else {
 
210
        QGlyphLayout *g = glyphs + len;
 
211
        const QChar *c = str + len;
 
212
        if (mirrored) {
 
213
            while (c != str)
 
214
                (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : ::mirroredChar(*c).unicode();
 
215
        } else {
 
216
            while (c != str)
 
217
                (--g)->glyph = (--c)->unicode() == 0xa0 ? 0x20 : c->unicode();
 
218
        }
 
219
    }
 
220
    *nglyphs = len;
 
221
 
 
222
    QGlyphLayout *g = glyphs + len;
 
223
    XCharStruct *xcs;
 
224
    // inlined for better perfomance
 
225
    if (!_fs->per_char) {
 
226
        xcs = &_fs->min_bounds;
 
227
        while (g != glyphs) {
 
228
            --g;
 
229
            g->advance.rx() = xcs->width;
 
230
            g->advance.ry() = 0;
 
231
        }
 
232
    }
 
233
    else if (!_fs->max_byte1) {
 
234
        XCharStruct *base = _fs->per_char - _fs->min_char_or_byte2;
 
235
        while (g != glyphs) {
 
236
            unsigned int gl = (--g)->glyph;
 
237
            xcs = (gl >= _fs->min_char_or_byte2 && gl <= _fs->max_char_or_byte2) ?
 
238
                  base + gl : 0;
 
239
            g->advance.rx() = (!xcs || (!xcs->width && !xcs->ascent && !xcs->descent)) ? _fs->ascent : xcs->width;
 
240
            g->advance.ry() = 0;
 
241
        }
 
242
    }
 
243
    else {
 
244
        while (g != glyphs) {
 
245
            xcs = charStruct(_fs, (--g)->glyph);
 
246
            g->advance.rx() = xcs ? xcs->width : _fs->ascent;
 
247
            g->advance.ry() = 0;
 
248
        }
 
249
    }
 
250
    return true;
 
251
}
 
252
 
 
253
glyph_metrics_t QFontEngineXLFD::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
 
254
{
 
255
    int i;
 
256
 
 
257
    glyph_metrics_t overall;
 
258
    qreal ymax = 0.;
 
259
    qreal xmax = 0.;
 
260
    for (i = 0; i < numGlyphs; i++) {
 
261
        XCharStruct *xcs = charStruct(_fs, glyphs[i].glyph);
 
262
        if (xcs) {
 
263
            qreal x = overall.xoff + glyphs[i].offset.x() - xcs->lbearing;
 
264
            qreal y = overall.yoff + glyphs[i].offset.y() - xcs->ascent;
 
265
            overall.x = qMin(overall.x, x);
 
266
            overall.y = qMin(overall.y, y);
 
267
            xmax = qMax(xmax, overall.xoff + glyphs[i].offset.x() + xcs->rbearing);
 
268
            ymax = qMax(ymax, y + xcs->ascent + xcs->descent);
 
269
            overall.xoff += glyphs[i].advance.x();
 
270
        } else {
 
271
            qreal size = _fs->ascent;
 
272
            overall.x = qMin(overall.x, overall.xoff);
 
273
            overall.y = qMin(overall.y, overall.yoff - size);
 
274
            ymax = qMax(ymax, overall.yoff);
 
275
            overall.xoff += size;
 
276
            xmax = qMax(xmax, overall.xoff);
 
277
        }
 
278
    }
 
279
    overall.height = ymax - overall.y;
 
280
    overall.width = xmax - overall.x;
 
281
 
 
282
    return overall;
 
283
}
 
284
 
 
285
glyph_metrics_t QFontEngineXLFD::boundingBox(glyph_t glyph)
 
286
{
 
287
    glyph_metrics_t gm;
 
288
    XCharStruct *xcs = charStruct(_fs, glyph);
 
289
    if (xcs) {
 
290
        gm = glyph_metrics_t(xcs->lbearing, -xcs->ascent, xcs->rbearing- xcs->lbearing, xcs->ascent + xcs->descent,
 
291
                              xcs->width, 0);
 
292
    } else {
 
293
        qreal size = ascent();
 
294
        gm = glyph_metrics_t(0, size, size, size, size, 0);
 
295
    }
 
296
    return gm;
 
297
}
 
298
 
 
299
 
 
300
qreal QFontEngineXLFD::ascent() const
 
301
{
 
302
    return _fs->ascent;
 
303
}
 
304
 
 
305
qreal QFontEngineXLFD::descent() const
 
306
{
 
307
    return (_fs->descent-1);
 
308
}
 
309
 
 
310
qreal QFontEngineXLFD::leading() const
 
311
{
 
312
    qreal l = (qMin<int>(_fs->ascent, _fs->max_bounds.ascent)
 
313
                 + qMin<int>(_fs->descent, _fs->max_bounds.descent)) * qreal(0.15);
 
314
    return ceil(l);
 
315
}
 
316
 
 
317
qreal QFontEngineXLFD::maxCharWidth() const
 
318
{
 
319
    return _fs->max_bounds.width;
 
320
}
 
321
 
 
322
 
 
323
// Loads the font for the specified script
 
324
static inline int maxIndex(XFontStruct *f) {
 
325
    return (((f->max_byte1 - f->min_byte1) *
 
326
             (f->max_char_or_byte2 - f->min_char_or_byte2 + 1)) +
 
327
            f->max_char_or_byte2 - f->min_char_or_byte2);
 
328
}
 
329
 
 
330
qreal QFontEngineXLFD::minLeftBearing() const
 
331
{
 
332
    if (lbearing == SHRT_MIN) {
 
333
        if (_fs->per_char) {
 
334
            XCharStruct *cs = _fs->per_char;
 
335
            int nc = maxIndex(_fs) + 1;
 
336
            int mx = cs->lbearing;
 
337
 
 
338
            for (int c = 1; c < nc; c++) {
 
339
                // ignore the bearings for characters whose ink is
 
340
                // completely outside the normal bounding box
 
341
                if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
 
342
                    (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
 
343
                    continue;
 
344
 
 
345
                int nmx = cs[c].lbearing;
 
346
 
 
347
                if (nmx < mx)
 
348
                    mx = nmx;
 
349
            }
 
350
 
 
351
            ((QFontEngineXLFD *)this)->lbearing = mx;
 
352
        } else
 
353
            ((QFontEngineXLFD *)this)->lbearing = _fs->min_bounds.lbearing;
 
354
    }
 
355
    return lbearing;
 
356
}
 
357
 
 
358
qreal QFontEngineXLFD::minRightBearing() const
 
359
{
 
360
    if (rbearing == SHRT_MIN) {
 
361
        if (_fs->per_char) {
 
362
            XCharStruct *cs = _fs->per_char;
 
363
            int nc = maxIndex(_fs) + 1;
 
364
            int mx = cs->rbearing;
 
365
 
 
366
            for (int c = 1; c < nc; c++) {
 
367
                // ignore the bearings for characters whose ink is
 
368
                // completely outside the normal bounding box
 
369
                if ((cs[c].lbearing <= 0 && cs[c].rbearing <= 0) ||
 
370
                    (cs[c].lbearing >= cs[c].width && cs[c].rbearing >= cs[c].width))
 
371
                    continue;
 
372
 
 
373
                int nmx = cs[c].rbearing;
 
374
 
 
375
                if (nmx < mx)
 
376
                    mx = nmx;
 
377
            }
 
378
 
 
379
            ((QFontEngineXLFD *)this)->rbearing = mx;
 
380
        } else
 
381
            ((QFontEngineXLFD *)this)->rbearing = _fs->min_bounds.rbearing;
 
382
    }
 
383
    return rbearing;
 
384
}
 
385
 
 
386
int QFontEngineXLFD::cmap() const
 
387
{
 
388
    return _cmap;
 
389
}
 
390
 
 
391
const char *QFontEngineXLFD::name() const
 
392
{
 
393
    return _name;
 
394
}
 
395
 
 
396
bool QFontEngineXLFD::canRender(const QChar *string, int len)
 
397
{
 
398
    QVarLengthArray<QGlyphLayout, 256> glyphs(len);
 
399
    int nglyphs = len;
 
400
    if (stringToCMap(string, len, glyphs.data(), &nglyphs, 0) == false) {
 
401
        glyphs.resize(nglyphs);
 
402
        stringToCMap(string, len, glyphs.data(), &nglyphs, 0);
 
403
    }
 
404
 
 
405
    bool allExist = true;
 
406
    for (int i = 0; i < nglyphs; i++) {
 
407
        if (!glyphs[i].glyph || !charStruct(_fs, glyphs[i].glyph)) {
 
408
            allExist = false;
 
409
            break;
 
410
        }
 
411
    }
 
412
 
 
413
    return allExist;
 
414
}
 
415
 
 
416
 
 
417
#ifndef QT_NO_FONTCONFIG
 
418
 
 
419
// ------------------------------------------------------------------
 
420
// Multi FT engine
 
421
// ------------------------------------------------------------------
 
422
 
 
423
#include FT_OUTLINE_H
 
424
 
 
425
QFontEngineMultiFT::QFontEngineMultiFT(FcFontSet *fs, int s)
 
426
    : QFontEngineMulti(fs->nfont), fontSet(fs), screen(s)
 
427
{
 
428
    loadEngine(0);
 
429
    cache_cost = 100;
 
430
}
 
431
 
 
432
QFontEngineMultiFT::~QFontEngineMultiFT()
 
433
{
 
434
    FcFontSetDestroy(fontSet);
 
435
}
 
436
 
 
437
void QFontEngineMultiFT::loadEngine(int at)
 
438
{
 
439
    Q_ASSERT(at < engines.size());
 
440
    Q_ASSERT(engines.at(at) == 0);
 
441
    FcPattern *pattern = fontSet->fonts[at];
 
442
    extern QFontDef FcPatternToQFontDef(FcPattern *pattern);
 
443
    QFontDef fontDef = FcPatternToQFontDef(fontSet->fonts[at]);
 
444
    // note: we use -1 for the script to make sure that we keep real
 
445
    // FT engines separate from Multi engines in the font cache
 
446
    QFontCache::Key key(fontDef, -1, screen);
 
447
    QFontEngine *fontEngine = QFontCache::instance->findEngine(key);
 
448
    if (!fontEngine) {
 
449
        FcConfigSubstitute(0, pattern, FcMatchPattern);
 
450
        FcDefaultSubstitute(pattern);
 
451
        FcResult res;
 
452
        FcPattern *match = FcFontMatch(0, pattern, &res);
 
453
        QFontEngineFT *engine = new QFontEngineFT(match, fontDef, screen);
 
454
        if (engine->invalid())
 
455
            delete engine;
 
456
        else
 
457
            fontEngine = engine;
 
458
        if (!fontEngine) {
 
459
            fontEngine = new QFontEngineBox(fontDef.pixelSize);
 
460
            fontEngine->fontDef = fontDef;
 
461
        }
 
462
        QFontCache::instance->insertEngine(key, fontEngine);
 
463
    }
 
464
    fontEngine->ref.ref();
 
465
    engines[at] = fontEngine;
 
466
}
 
467
 
 
468
 
 
469
// ------------------------------------------------------------------
 
470
// FT font engine
 
471
// ------------------------------------------------------------------
 
472
 
 
473
/*
 
474
 * Freetype 2.1.7 and earlier used width/height
 
475
 * for matching sizes in the BDF and PCF loaders.
 
476
 * This has been fixed for 2.1.8.
 
477
 */
 
478
#if HAVE_FT_BITMAP_SIZE_Y_PPEM
 
479
#define X_SIZE(face,i) ((face)->available_sizes[i].x_ppem)
 
480
#define Y_SIZE(face,i) ((face)->available_sizes[i].y_ppem)
 
481
#else
 
482
#define X_SIZE(face,i) ((face)->available_sizes[i].width << 6)
 
483
#define Y_SIZE(face,i) ((face)->available_sizes[i].height << 6)
 
484
#endif
 
485
 
 
486
void QFontEngineFT::computeSize()
 
487
{
 
488
    ysize = fontDef.pixelSize << 6;
 
489
    xsize = ysize * fontDef.stretch / 100;
 
490
 
 
491
    FT_Face face = freetype->face;
 
492
    /*
 
493
     * Bitmap only faces must match exactly, so find the closest
 
494
     * one (height dominant search)
 
495
     */
 
496
    if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
 
497
        int best = 0;
 
498
        for (int i = 1; i < face->num_fixed_sizes; i++) {
 
499
            if (qAbs(ysize -  Y_SIZE(face,i)) <
 
500
                qAbs (ysize - Y_SIZE(face, best)) ||
 
501
                (qAbs (ysize - Y_SIZE(face, i)) ==
 
502
                 qAbs (ysize - Y_SIZE(face, best)) &&
 
503
                 qAbs (xsize - X_SIZE(face, i)) <
 
504
                 qAbs (xsize - X_SIZE(face, best)))) {
 
505
                best = i;
 
506
            }
 
507
        }
 
508
        if (FT_Set_Char_Size (face, X_SIZE(face, best), Y_SIZE(face, best), 0, 0) == 0) {
 
509
            xsize = X_SIZE(face, best);
 
510
            ysize = Y_SIZE(face, best);
 
511
        } else
 
512
            xsize = ysize = 0;
 
513
    }
 
514
}
 
515
 
 
516
 
 
517
static FT_Library library = 0;
 
518
QHash<QFreetypeFaceId, QFreetypeFace *> *QFontEngineFT::freetypeFaces = 0;
 
519
 
 
520
QFontEngineFT::Glyph::~Glyph()
 
521
{
 
522
    delete [] data;
 
523
}
 
524
 
 
525
static QFreetypeFaceId face_id(FcPattern *pattern)
 
526
{
 
527
    char *file_name;
 
528
    FcPatternGetString(pattern, FC_FILE, 0, (FcChar8 **)&file_name);
 
529
    int face_index;
 
530
    if (!FcPatternGetInteger(pattern, FC_INDEX, 0, &face_index))
 
531
        face_index = 0;
 
532
    QFreetypeFaceId face_id;
 
533
    face_id.filename = file_name;
 
534
    face_id.index = face_index;
 
535
    return face_id;
 
536
}
 
537
 
 
538
QFontEngineFT::QFontEngineFT(FcPattern *pattern, const QFontDef &fd, int screen)
 
539
{
 
540
    cache_cost = 100;
 
541
    fontDef = fd;
 
542
    _pattern = pattern;
 
543
//     FcPatternPrint(pattern);
 
544
 
 
545
    antialias = X11->fc_antialias;
 
546
    FcBool b;
 
547
    if (FcPatternGetBool(pattern, FC_ANTIALIAS, 0, &b) == FcResultMatch)
 
548
        antialias = b;
 
549
    if (FcPatternGetInteger(pattern, FC_RGBA, 0, &subpixel) == FcResultNoMatch)
 
550
        subpixel = X11->screens[screen].subpixel;
 
551
    if (!antialias || subpixel == FC_RGBA_UNKNOWN)
 
552
        subpixel = FC_RGBA_NONE;
 
553
 
 
554
    if (!library)
 
555
        FT_Init_FreeType(&library);
 
556
 
 
557
    if (!freetypeFaces)
 
558
        freetypeFaces = new QHash<QFreetypeFaceId, QFreetypeFace *>();
 
559
 
 
560
    QFreetypeFaceId face_id = ::face_id(pattern);
 
561
 
 
562
    freetype = freetypeFaces->value(face_id, 0);
 
563
    if (!freetype) {
 
564
        freetype = new QFreetypeFace;
 
565
        freetype->ref = 0;
 
566
        freetype->lock = 0;
 
567
        freetype->xsize = 0;
 
568
        freetype->ysize = 0;
 
569
        FcCharSet *cs;
 
570
        FcPatternGetCharSet (pattern, FC_CHARSET, 0, &cs);
 
571
        freetype->charset = FcCharSetCopy(cs);
 
572
 
 
573
        memset(freetype->cmapCache, 0, sizeof(freetype->cmapCache));
 
574
        FT_New_Face(library, face_id.filename, face_id.index, &freetype->face);
 
575
        freetypeFaces->insert(face_id, freetype);
 
576
    }
 
577
    freetype->ref.ref();
 
578
 
 
579
    lbearing = rbearing = SHRT_MIN;
 
580
    computeSize();
 
581
    outline_drawing = xsize > (64<<6) || ysize > (64<<6);
 
582
 
 
583
    lockFace();
 
584
 
 
585
    //underline metrics
 
586
    FT_Face face = freetype->face;
 
587
    if (FT_IS_SCALABLE(face)) {
 
588
        line_thickness =  FT_MulFix(face->underline_thickness, face->size->metrics.y_scale)/64.;
 
589
        underline_position = -FT_MulFix(face->underline_position, face->size->metrics.y_scale)/64.;
 
590
    } else {
 
591
        // copied from QFontEngineQPF
 
592
        // ad hoc algorithm
 
593
        int score = fontDef.weight * fontDef.pixelSize;
 
594
        line_thickness = score / 700;
 
595
        // looks better with thicker line for small pointsizes
 
596
        if (line_thickness < 2 && score >= 1050)
 
597
            line_thickness = 2;
 
598
        underline_position =  ((line_thickness * 2) + 3) / 6;
 
599
    }
 
600
    if (line_thickness < 1)
 
601
        line_thickness = 1;
 
602
 
 
603
    metrics = freetype->face->size->metrics;
 
604
 
 
605
    int load_flags = FT_LOAD_DEFAULT;
 
606
    int format = PictStandardA8;
 
607
    if (!antialias) {
 
608
        load_flags |= FT_LOAD_TARGET_MONO;
 
609
        format = PictStandardA1;
 
610
    } else {
 
611
        if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
 
612
            load_flags |= FT_LOAD_TARGET_LCD;
 
613
            format = PictStandardARGB32;
 
614
        } else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
 
615
            load_flags |= FT_LOAD_TARGET_LCD_V;
 
616
            format = PictStandardARGB32;
 
617
        }
 
618
    }
 
619
 
 
620
    unlockFace();
 
621
    glyphSet = XRenderCreateGlyphSet(X11->display, XRenderFindStandardFormat(X11->display, format));
 
622
    _openType = 0;
 
623
}
 
624
 
 
625
QFontEngineFT::~QFontEngineFT()
 
626
{
 
627
    if (!freetype->ref.deref()) {
 
628
        FT_Done_Face(freetype->face);
 
629
        FcCharSetDestroy(freetype->charset);
 
630
        delete freetype;
 
631
        freetypeFaces->take(::face_id(_pattern));
 
632
    }
 
633
    if (!freetypeFaces->size()) {
 
634
        delete freetypeFaces;
 
635
        freetypeFaces = 0;
 
636
        FT_Done_FreeType(library);
 
637
        library = 0;
 
638
    }
 
639
    FcPatternDestroy(_pattern);
 
640
    _pattern = 0;
 
641
 
 
642
    qDeleteAll(glyph_data);
 
643
    XRenderFreeGlyphSet(X11->display, glyphSet);
 
644
    delete _openType;
 
645
}
 
646
 
 
647
FT_Face QFontEngineFT::lockFace() const
 
648
{
 
649
    Q_ASSERT(freetype->lock == 0);
 
650
    while (!freetype->lock.testAndSet(0, 1))
 
651
        usleep(100);
 
652
    FT_Face face = freetype->face;
 
653
    if (freetype->xsize != xsize && freetype->ysize != ysize) {
 
654
        FT_Set_Char_Size(face, xsize, ysize, 0, 0);
 
655
        freetype->xsize = xsize;
 
656
        freetype->ysize = ysize;
 
657
    }
 
658
    return face;
 
659
}
 
660
 
 
661
void QFontEngineFT::unlockFace() const
 
662
{
 
663
    if (!freetype->lock.testAndSet(1, 0))
 
664
        Q_ASSERT(false);
 
665
}
 
666
 
 
667
#define FLOOR(x)    ((x) & -64)
 
668
#define CEIL(x)     (((x)+63) & -64)
 
669
#define TRUNC(x)    ((x) >> 6)
 
670
#define ROUND(x)    (((x)+32) & -64)
 
671
 
 
672
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(uint glyph, GlyphFormat format) const
 
673
{
 
674
    Q_ASSERT(freetype->lock == 1);
 
675
 
 
676
    bool add_to_glyphset = false;
 
677
    if (format == Format_None) {
 
678
        format = Format_Mono;
 
679
        if (X11->use_xrender) {
 
680
            add_to_glyphset = true;
 
681
            if (subpixel != FC_RGBA_NONE)
 
682
                format = Format_A32;
 
683
            else if (antialias)
 
684
                format = Format_A8;
 
685
        }
 
686
    }
 
687
    Q_ASSERT(format != Format_None);
 
688
    int hfactor = 1;
 
689
    int vfactor = 1;
 
690
    int load_flags = FT_LOAD_DEFAULT;
 
691
    if (outline_drawing) {
 
692
        load_flags = FT_LOAD_NO_BITMAP|FT_LOAD_NO_HINTING;
 
693
    } else if (format == Format_Mono) {
 
694
        load_flags |= FT_LOAD_TARGET_MONO;
 
695
    } else if (format == Format_A32) {
 
696
        if (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_BGR) {
 
697
            load_flags |= FT_LOAD_TARGET_LCD;
 
698
            hfactor = 3;
 
699
        } else if (subpixel == FC_RGBA_VRGB || subpixel == FC_RGBA_VBGR) {
 
700
            load_flags |= FT_LOAD_TARGET_LCD_V;
 
701
            vfactor = 3;
 
702
        }
 
703
 
 
704
    }
 
705
 
 
706
    {
 
707
        Glyph *g = glyph_data.value(glyph);
 
708
        if (g && g->format == format)
 
709
            return g;
 
710
    }
 
711
 
 
712
    FT_Face face = freetype->face;
 
713
    FT_Load_Glyph(face, glyph, load_flags);
 
714
 
 
715
    if (outline_drawing)
 
716
        return 0;
 
717
 
 
718
    FT_GlyphSlot slot = face->glyph;
 
719
 
 
720
    int left  = FLOOR(slot->metrics.horiBearingX);
 
721
    int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
 
722
    int top    = CEIL(slot->metrics.horiBearingY);
 
723
    int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
 
724
 
 
725
    XGlyphInfo info;
 
726
    info.width = TRUNC(right - left);
 
727
    info.height = TRUNC(top - bottom);
 
728
    info.x = -TRUNC(left);
 
729
    info.y = TRUNC(top);
 
730
    info.xOff = TRUNC(ROUND(slot->advance.x));
 
731
    info.yOff = 0;
 
732
 
 
733
    int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
 
734
                 (format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
 
735
    int size = pitch * info.height * vfactor;
 
736
    uchar *buffer = new uchar[size];
 
737
    memset (buffer, 0, size);
 
738
 
 
739
    if (slot->format == FT_GLYPH_FORMAT_OUTLINE) {
 
740
        FT_Bitmap bitmap;
 
741
        bitmap.rows = info.height*vfactor;
 
742
        bitmap.width = info.width*hfactor;
 
743
        bitmap.pitch = pitch;
 
744
        bitmap.buffer = buffer;
 
745
        bitmap.pixel_mode = format == Format_Mono ? ft_pixel_mode_mono : ft_pixel_mode_grays;
 
746
        FT_Matrix matrix;
 
747
        matrix.xx = hfactor << 16;
 
748
        matrix.yy = vfactor << 16;
 
749
        matrix.yx = matrix.xy = 0;
 
750
 
 
751
        FT_Outline_Transform(&slot->outline, &matrix);
 
752
        FT_Outline_Translate (&slot->outline, -left*hfactor, -bottom*vfactor);
 
753
        FT_Outline_Get_Bitmap(library, &slot->outline, &bitmap);
 
754
        if (hfactor != 1) {
 
755
            Q_ASSERT (bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);
 
756
            Q_ASSERT(antialias);
 
757
            uchar *src = buffer;
 
758
            size = info.width * 4 * info.height;
 
759
            uchar *newBuf = new uchar[size];
 
760
            uint *dst = (uint *)newBuf;
 
761
            int h = info.height;
 
762
            const uint r = (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_VRGB) ? 16 : 0;
 
763
            const uint b = 16 - r;
 
764
            while (h--) {
 
765
                uint *dd = dst;
 
766
                for (int x = 0; x < bitmap.width; x += 3) {
 
767
                    // ############# filter
 
768
                    uint res = (src[x] << r) + (src[x+1] << 8) + (src[x+2] << b);
 
769
                    *dd = res;
 
770
                    ++dd;
 
771
                }
 
772
                dst += info.width;
 
773
                src += bitmap.pitch;
 
774
            }
 
775
            delete [] buffer;
 
776
            buffer = newBuf;
 
777
        } else if (vfactor != 1) {
 
778
            uchar *src = buffer;
 
779
            size = info.width * 4 * info.height;
 
780
            uchar *newBuf = new uchar[size];
 
781
            uint *dst = (uint *)newBuf;
 
782
            int h = info.height;
 
783
            const uint r = (subpixel == FC_RGBA_RGB || subpixel == FC_RGBA_VRGB) ? 16 : 0;
 
784
            const uint b = 16 - r;
 
785
            while (h--) {
 
786
                for (int x = 0; x < info.width; x++) {
 
787
                    // ############# filter
 
788
                    uint res = src[x] << r + src[x+bitmap.pitch] << 8 + src[x+2*bitmap.pitch] << b;
 
789
                    dst[x] = res;
 
790
                }
 
791
                dst += info.width;
 
792
                src += 3*bitmap.pitch;
 
793
            }
 
794
            delete [] buffer;
 
795
            buffer = newBuf;
 
796
        }
 
797
    } else if (slot->format == FT_GLYPH_FORMAT_BITMAP) {
 
798
        Q_ASSERT(slot->bitmap.pixel_mode == FT_PIXEL_MODE_MONO);
 
799
        uchar *src = slot->bitmap.buffer;
 
800
        uchar *dst = buffer;
 
801
        int h = slot->bitmap.rows;
 
802
        if (format == Format_Mono) {
 
803
            int bytes = ((info.width + 7) & ~7) >> 3;
 
804
            while (h--) {
 
805
                memcpy (dst, src, bytes);
 
806
                dst += pitch;
 
807
                src += slot->bitmap.pitch;
 
808
            }
 
809
        } else {
 
810
            if (hfactor != 1) {
 
811
                while (h--) {
 
812
                    uchar *dd = dst;
 
813
                    for (int x = 0; x < slot->bitmap.width; x++) {
 
814
                        unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
 
815
                        *dd++ = a;
 
816
                        *dd++ = a;
 
817
                        *dd++ = a;
 
818
                        *dd++ = a;
 
819
                    }
 
820
                    dst += pitch * vfactor;
 
821
                    src += slot->bitmap.pitch;
 
822
                }
 
823
 
 
824
            } else if (vfactor != 1) {
 
825
                while (h--) {
 
826
                    for (int x = 0; x < slot->bitmap.width; x++) {
 
827
                        unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
 
828
                        dst[x] = a;
 
829
                    }
 
830
                    memcpy(dst + pitch, dst, pitch);
 
831
                    dst += pitch;
 
832
                    memcpy(dst + pitch, dst, pitch);
 
833
                    dst += pitch;
 
834
                    src += slot->bitmap.pitch;
 
835
                }
 
836
            } else {
 
837
                while (h--) {
 
838
                    for (int x = 0; x < slot->bitmap.width; x++) {
 
839
                        unsigned char a = ((src[x >> 3] & (0x80 >> (x & 7))) ? 0xff : 0x00);
 
840
                        dst[x] = a;
 
841
                    }
 
842
                    dst += pitch;
 
843
                    src += slot->bitmap.pitch;
 
844
                }
 
845
            }
 
846
        }
 
847
    } else {
 
848
        qWarning("glyph neither outline nor bitmap");
 
849
        return 0;
 
850
    }
 
851
 
 
852
#ifndef QT_NO_XRENDER
 
853
    if (add_to_glyphset) {
 
854
        if (format == Format_Mono) {
 
855
            /*
 
856
             * swap bit order around; FreeType is always MSBFirst
 
857
             */
 
858
            if (BitmapBitOrder(X11->display) != MSBFirst) {
 
859
                unsigned char *line = (unsigned char *) buffer;
 
860
                int i = size;
 
861
                i = size;
 
862
                while (i--) {
 
863
                    unsigned char c;
 
864
                    c = *line;
 
865
                    c = ((c << 1) & 0xaa) | ((c >> 1) & 0x55);
 
866
                    c = ((c << 2) & 0xcc) | ((c >> 2) & 0x33);
 
867
                    c = ((c << 4) & 0xf0) | ((c >> 4) & 0x0f);
 
868
                    *line++ = c;
 
869
                }
 
870
            }
 
871
        }
 
872
 
 
873
        ::Glyph xglyph = glyph;
 
874
        XRenderAddGlyphs (X11->display, glyphSet, &xglyph, &info, 1, (const char *)buffer, size);
 
875
        delete [] buffer;
 
876
        buffer = 0;
 
877
    }
 
878
#endif
 
879
 
 
880
 
 
881
    bool large_glyph = (((signed char)(slot->linearHoriAdvance>>16) != slot->linearHoriAdvance>>16)
 
882
                        || ((uchar)(info.width) != info.width)
 
883
                        || ((uchar)(info.height) != info.height)
 
884
                        || ((signed char)(info.x) != info.x)
 
885
                        || ((signed char)(info.y) != info.y)
 
886
                        || ((signed char)(info.xOff) != info.xOff));
 
887
 
 
888
    if (large_glyph) {
 
889
//         qDebug("got a large glyph!");
 
890
        return 0;
 
891
    }
 
892
 
 
893
    Glyph *g = new Glyph;
 
894
 
 
895
    g->linearAdvance = slot->linearHoriAdvance >> 10;
 
896
    g->width = TRUNC(right - left);
 
897
    g->height = TRUNC(top - bottom);
 
898
    g->x = -TRUNC(left);
 
899
    g->y = TRUNC(top);
 
900
    g->advance = TRUNC(ROUND(slot->advance.x));
 
901
    g->format = add_to_glyphset ? Format_None : format;
 
902
    g->data = buffer;
 
903
 
 
904
    // make sure we delete the old cached glyph
 
905
    delete glyph_data.value(glyph);
 
906
    glyph_data[glyph] = g;
 
907
 
 
908
    return g;
 
909
}
 
910
 
 
911
#if 0
 
912
static inline glyph_t getAdobeCharIndex(FT_Face _face, int cmap, uint ucs4)
 
913
{
 
914
    // ############## save and restore charmap
 
915
    FT_Set_Charmap(_face, _face->charmaps[cmap]);
 
916
    glyph_t g = FT_Get_Char_Index(_face, ucs4);
 
917
    return g;
 
918
}
 
919
#endif
 
920
 
 
921
inline unsigned int getChar(const QChar *str, int &i, const int len)
 
922
{
 
923
    unsigned int uc = str[i].unicode();
 
924
    if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
 
925
        uint low = str[i+1].unicode();
 
926
       if (low >= 0xdc00 && low < 0xe000) {
 
927
            uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
 
928
            ++i;
 
929
        }
 
930
    }
 
931
    return uc;
 
932
}
 
933
 
 
934
bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
 
935
                                 QTextEngine::ShaperFlags flags) const
 
936
{
 
937
    if (*nglyphs < len) {
 
938
        *nglyphs = len;
 
939
        return false;
 
940
    }
 
941
 
 
942
    bool mirrored = flags & QTextEngine::RightToLeft;
 
943
    int glyph_pos = 0;
 
944
#if 0
 
945
    if (_cmap != -1) {
 
946
        FT_Face _face = lockFace();
 
947
       for ( int i = 0; i < len; ++i ) {
 
948
           unsigned int uc = getChar(str, i, len);
 
949
           glyphs[glyph_pos].glyph = uc < cmapCacheSize ? cmapCache[uc] : 0;
 
950
           if ( !glyphs[glyph_pos].glyph ) {
 
951
               glyph_t glyph = FT_Get_Char_Index(_face, uc);
 
952
               if (!glyph)
 
953
                   glyph = getAdobeCharIndex(_face, _cmap, uc);
 
954
              glyphs[glyph_pos].glyph = glyph;
 
955
               if ( uc < cmapCacheSize )
 
956
                    ((QFontEngineFT *)this)->cmapCache[uc] = glyph;
 
957
           }
 
958
           ++glyph_pos;
 
959
       }
 
960
        unlockFace();
 
961
    } else
 
962
#endif
 
963
    {
 
964
        FT_Face face = freetype->face;
 
965
        for (int i = 0; i < len; ++i) {
 
966
            unsigned int uc = getChar(str, i, len);
 
967
            if (mirrored)
 
968
                uc = QUnicodeTables::mirroredChar(uc);
 
969
            glyphs[glyph_pos].glyph = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
 
970
            if (!glyphs[glyph_pos].glyph && FcCharSetHasChar(freetype->charset, uc)) {
 
971
            redo:
 
972
                glyph_t glyph = FT_Get_Char_Index(face, uc);
 
973
                if (!glyph && (uc == 0xa0 || uc == 0x9)) {
 
974
                    uc = 0x20;
 
975
                    goto redo;
 
976
                }
 
977
                glyphs[glyph_pos].glyph = glyph;
 
978
                if (uc < QFreetypeFace::cmapCacheSize)
 
979
                    freetype->cmapCache[uc] = glyph;
 
980
            }
 
981
            ++glyph_pos;
 
982
        }
 
983
    }
 
984
 
 
985
    *nglyphs = glyph_pos;
 
986
    recalcAdvances(*nglyphs, glyphs, flags);
 
987
 
 
988
    return true;
 
989
}
 
990
 
 
991
void QFontEngineFT::recalcAdvances(int len, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
 
992
{
 
993
    FT_Face face = 0;
 
994
    if (flags & QTextEngine::DesignMetrics) {
 
995
        for (int i = 0; i < len; i++) {
 
996
            Glyph *g = glyph_data.value(glyphs[i].glyph);
 
997
            if (!g) {
 
998
                if (!face)
 
999
                    face = lockFace();
 
1000
                g = loadGlyph(glyphs[i].glyph);
 
1001
            }
 
1002
            // for uncachable glyph, get advance from glyphslot
 
1003
            glyphs[i].advance.rx() = g ? g->linearAdvance/65536. : face->glyph->linearHoriAdvance/65536.;
 
1004
            glyphs[i].advance.ry() = 0.;
 
1005
        }
 
1006
    } else {
 
1007
        for (int i = 0; i < len; i++) {
 
1008
            Glyph *g = glyph_data.value(glyphs[i].glyph);
 
1009
            if (!g) {
 
1010
                if (!face)
 
1011
                    face = lockFace();
 
1012
                g = loadGlyph(glyphs[i].glyph);
 
1013
            }
 
1014
            // for uncachable glyph, get advance from glyphslot
 
1015
            glyphs[i].advance.rx() = g ? g->advance : face->glyph->metrics.horiAdvance/64.;
 
1016
            glyphs[i].advance.ry() = 0.;
 
1017
        }
 
1018
    }
 
1019
    if (face)
 
1020
        unlockFace();
 
1021
}
 
1022
 
 
1023
glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout *glyphs, int numGlyphs)
 
1024
{
 
1025
 
 
1026
    FT_Face face = 0;
 
1027
 
 
1028
    glyph_metrics_t overall;
 
1029
    qreal ymax = 0;
 
1030
    qreal xmax = 0;
 
1031
    for (int i = 0; i < numGlyphs; i++) {
 
1032
        Glyph *g = glyph_data.value(glyphs[i].glyph);
 
1033
        if (!g) {
 
1034
            if (!face)
 
1035
                face = lockFace();
 
1036
            g = loadGlyph(glyphs[i].glyph);
 
1037
        }
 
1038
        if (g) {
 
1039
            qreal x = overall.xoff + glyphs[i].offset.x() - g->x;
 
1040
            qreal y = overall.yoff + glyphs[i].offset.y() - g->y;
 
1041
            overall.x = qMin(overall.x, x);
 
1042
            overall.y = qMin(overall.y, y);
 
1043
            xmax = qMax(xmax, x + g->width);
 
1044
            ymax = qMax(ymax, y + g->height);
 
1045
            overall.xoff += qRound(g->advance);
 
1046
        } else {
 
1047
            int left  = FLOOR(face->glyph->metrics.horiBearingX);
 
1048
            int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
 
1049
            int top    = CEIL(face->glyph->metrics.horiBearingY);
 
1050
            int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
 
1051
 
 
1052
            qreal x = overall.xoff + glyphs[i].offset.x() - (-TRUNC(left));
 
1053
            qreal y = overall.yoff + glyphs[i].offset.y() - TRUNC(top);
 
1054
            overall.x = qMin(overall.x, x);
 
1055
            overall.y = qMin(overall.y, y);
 
1056
            xmax = qMax(xmax, x + TRUNC(right - left));
 
1057
            ymax = qMax(ymax, y + TRUNC(top - bottom));
 
1058
            overall.xoff += qRound(TRUNC(ROUND(face->glyph->advance.x)));
 
1059
        }
 
1060
    }
 
1061
    overall.height = ymax - overall.y;
 
1062
    overall.width = xmax - overall.x;
 
1063
 
 
1064
    if (face)
 
1065
        unlockFace();
 
1066
 
 
1067
    return overall;
 
1068
}
 
1069
 
 
1070
glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
 
1071
{
 
1072
    FT_Face face = 0;
 
1073
    glyph_metrics_t overall;
 
1074
    Glyph *g = glyph_data.value(glyph);
 
1075
    if (!g) {
 
1076
        face = lockFace();
 
1077
        g = loadGlyph(glyph);
 
1078
    }
 
1079
    if (g) {
 
1080
        overall.x = g->x;
 
1081
        overall.y = -g->y;
 
1082
        overall.width = g->width;
 
1083
        overall.height = g->height;
 
1084
        overall.xoff = g->advance;
 
1085
    } else {
 
1086
        int left  = FLOOR(face->glyph->metrics.horiBearingX);
 
1087
        int right = CEIL(face->glyph->metrics.horiBearingX + face->glyph->metrics.width);
 
1088
        int top    = CEIL(face->glyph->metrics.horiBearingY);
 
1089
        int bottom = FLOOR(face->glyph->metrics.horiBearingY - face->glyph->metrics.height);
 
1090
 
 
1091
        overall.width = TRUNC(right-left);
 
1092
        overall.height = TRUNC(top-bottom);
 
1093
        overall.x = TRUNC(left);
 
1094
        overall.y = -TRUNC(top);
 
1095
        overall.xoff = TRUNC(ROUND(face->glyph->advance.x));
 
1096
    }
 
1097
    if (face)
 
1098
        unlockFace();
 
1099
    return overall;
 
1100
}
 
1101
 
 
1102
bool QFontEngineFT::canRender(const QChar *string, int len)
 
1103
{
 
1104
    FT_Face face = freetype->face;
 
1105
#if 0
 
1106
    if (_cmap != -1) {
 
1107
        lockFace();
 
1108
        for ( int i = 0; i < len; i++ ) {
 
1109
            unsigned int uc = getChar(string, i, len);
 
1110
            if (!FcCharSetHasChar (_font->charset, uc) && getAdobeCharIndex(face, _cmap, uc) == 0) {
 
1111
                allExist = false;
 
1112
                break;
 
1113
            }
 
1114
        }
 
1115
        unlockFace();
 
1116
    } else
 
1117
#endif
 
1118
    {
 
1119
        for ( int i = 0; i < len; i++ ) {
 
1120
            unsigned int uc = getChar(string, i, len);
 
1121
            if (!FT_Get_Char_Index(face, uc))
 
1122
                    return false;
 
1123
        }
 
1124
    }
 
1125
    return true;
 
1126
}
 
1127
 
 
1128
void QFontEngineFT::doKerning(int num_glyphs, QGlyphLayout *g, QTextEngine::ShaperFlags flags) const
 
1129
{
 
1130
    if (!FT_HAS_KERNING(freetype->face))
 
1131
        return;
 
1132
    FT_Face face = lockFace();
 
1133
    uint f = (flags == QTextEngine::DesignMetrics ? FT_KERNING_UNFITTED : FT_KERNING_DEFAULT);
 
1134
    for (int i = 0; i < num_glyphs-1; ++i) {
 
1135
        FT_Vector kerning;
 
1136
        FT_Get_Kerning(face, g[i].glyph, g[i+1].glyph, f, &kerning);
 
1137
        g[i].advance.rx() += kerning.x / 64.;
 
1138
        g[i].advance.ry() += kerning.y / 64.;
 
1139
    }
 
1140
    unlockFace();
 
1141
}
 
1142
 
 
1143
static void addCurve(QPainterPath *path, const QPointF &cp, const QPointF &endPoint,
 
1144
                     int startOff, int nOff, FT_GlyphSlot g)
 
1145
{
 
1146
    int j;
 
1147
    QPointF c0 = QPointF(g->outline.points[startOff-1].x/64., -g->outline.points[startOff-1].y/64.);
 
1148
    QPointF current = QPointF(g->outline.points[startOff].x/64., -g->outline.points[startOff].y/64.);
 
1149
    for(j = 1; j <= nOff; j++) {
 
1150
        QPointF next = (j == nOff)
 
1151
                       ? endPoint
 
1152
                       : QPointF(g->outline.points[startOff + j].x/64., -g->outline.points[startOff + j].y/64.);
 
1153
        QPointF c3 = (j == nOff) ? next : (next + current)/2;
 
1154
        QPointF c1 = (2*current + c0)/3;
 
1155
        QPointF c2 = (2*current + c3)/3;
 
1156
//         qDebug("cubicTo %f/%f %f/%f %f/%f", (cp + c1).x(), (cp + c1).y(),
 
1157
//                (cp + c2).x(), (cp + c2).y(), (cp + c3).x(), (cp + c3).y());
 
1158
        path->cubicTo(cp + c1, cp + c2, cp + c3);
 
1159
        c0 = c3;
 
1160
        current = next;
 
1161
    }
 
1162
}
 
1163
 
 
1164
void QFontEngineFT::addOutlineToPath(qreal x, qreal y, const QGlyphLayout *glyphs, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags flags)
 
1165
{
 
1166
    if (FT_IS_SCALABLE(freetype->face)) {
 
1167
        FT_Face face = lockFace();
 
1168
        QPointF point = QPointF(x, y);
 
1169
        if (flags & QTextItem::RightToLeft) {
 
1170
            for (int gl = 0; gl < numGlyphs; gl++)
 
1171
                point += glyphs[gl].advance;
 
1172
        }
 
1173
        for (int gl = 0; gl < numGlyphs; gl++) {
 
1174
            FT_UInt glyph = glyphs[gl].glyph;
 
1175
            if (flags & QTextItem::RightToLeft)
 
1176
                point -= glyphs[gl].advance;
 
1177
            QPointF cp = point + glyphs[gl].offset;
 
1178
            if (!(flags & QTextItem::RightToLeft))
 
1179
                point += glyphs[gl].advance;
 
1180
 
 
1181
            FT_Load_Glyph(face, glyph, FT_LOAD_NO_HINTING|FT_LOAD_NO_BITMAP);
 
1182
 
 
1183
            FT_GlyphSlot g = face->glyph;
 
1184
            if (g->format != FT_GLYPH_FORMAT_OUTLINE)
 
1185
                continue;
 
1186
 
 
1187
            // convert the outline to a painter path
 
1188
            int i = 0;
 
1189
            for (int c = 0; c < g->outline.n_contours; ++c) {
 
1190
                QPointF p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
 
1191
//                 qDebug("contour: %d -- %d", i, g->outline.contours[c]);
 
1192
//                 qDebug("first point at %f %f", p.x(), p.y());
 
1193
                path->moveTo(p);
 
1194
 
 
1195
                int first = i;
 
1196
                int startOff = 0;
 
1197
                int nOff = 0;
 
1198
                ++i;
 
1199
                while (i <= g->outline.contours[c]) {
 
1200
                    QPointF p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
 
1201
//                     qDebug("     point at %f %f, on curve=%d", p.x(), p.y(), g->outline.tags[i] & 1);
 
1202
                    if (!(g->outline.tags[i] & 1)) {
 
1203
                        /* Off curve */
 
1204
                        if (!startOff) {
 
1205
                            startOff = i;
 
1206
                            nOff = 1;
 
1207
                        } else {
 
1208
                            ++nOff;
 
1209
                        }
 
1210
                    } else {
 
1211
                        /* On Curve */
 
1212
                        if (startOff) {
 
1213
                            // ###### fix 3rd order beziers
 
1214
                            addCurve(path, cp, QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.),
 
1215
                                     startOff, nOff, g);
 
1216
                            startOff = 0;
 
1217
                        } else {
 
1218
                            p = cp + QPointF(g->outline.points[i].x/64., -g->outline.points[i].y/64.);
 
1219
                            path->lineTo(p);
 
1220
                        }
 
1221
                    }
 
1222
                    ++i;
 
1223
                }
 
1224
                QPointF end(g->outline.points[first].x/64., -g->outline.points[first].y/64.);
 
1225
                if (startOff)
 
1226
                    addCurve(path, cp, end, startOff, nOff, g);
 
1227
                else
 
1228
                    path->lineTo(end + cp);
 
1229
            }
 
1230
        }
 
1231
        unlockFace();
 
1232
    } else {
 
1233
        addBitmapFontToPath(x, y, glyphs, numGlyphs, path, flags);
 
1234
    }
 
1235
}
 
1236
 
 
1237
qreal QFontEngineFT::ascent() const
 
1238
{
 
1239
    return TRUNC(ROUND(metrics.ascender));
 
1240
}
 
1241
 
 
1242
qreal QFontEngineFT::descent() const
 
1243
{
 
1244
    return -TRUNC(ROUND(metrics.descender)) + 1;
 
1245
}
 
1246
 
 
1247
qreal QFontEngineFT::leading() const
 
1248
{
 
1249
    return (metrics.height - metrics.ascender + metrics.descender) >> 6;
 
1250
}
 
1251
 
 
1252
qreal QFontEngineFT::maxCharWidth() const
 
1253
{
 
1254
    return metrics.max_advance >> 6;
 
1255
}
 
1256
 
 
1257
static const ushort char_table[] = {
 
1258
        40,
 
1259
        67,
 
1260
        70,
 
1261
        75,
 
1262
        86,
 
1263
        88,
 
1264
        89,
 
1265
        91,
 
1266
        102,
 
1267
        114,
 
1268
        124,
 
1269
        127,
 
1270
        205,
 
1271
        645,
 
1272
        884,
 
1273
        922,
 
1274
        1070,
 
1275
        12386
 
1276
};
 
1277
 
 
1278
static const int char_table_entries = sizeof(char_table)/sizeof(ushort);
 
1279
 
 
1280
 
 
1281
qreal QFontEngineFT::minLeftBearing() const
 
1282
{
 
1283
    if (lbearing == SHRT_MIN)
 
1284
        (void) minRightBearing(); // calculates both
 
1285
    return lbearing;
 
1286
}
 
1287
 
 
1288
qreal QFontEngineFT::minRightBearing() const
 
1289
{
 
1290
    if (rbearing == SHRT_MIN) {
 
1291
        lbearing = rbearing = 0;
 
1292
        const QChar *ch = (const QChar *)char_table;
 
1293
        QGlyphLayout glyphs[char_table_entries];
 
1294
        int ng = char_table_entries;
 
1295
        stringToCMap(ch, char_table_entries, glyphs, &ng, 0);
 
1296
        while (--ng) {
 
1297
            if (glyphs[ng].glyph) {
 
1298
                glyph_metrics_t gi = ((QFontEngineFT *)this)->boundingBox(glyphs[ng].glyph);
 
1299
                lbearing = qMin(lbearing, gi.x);
 
1300
                rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
 
1301
            }
 
1302
        }
 
1303
    }
 
1304
    return rbearing;
 
1305
}
 
1306
 
 
1307
qreal QFontEngineFT::lineThickness() const
 
1308
{
 
1309
    return line_thickness;
 
1310
}
 
1311
 
 
1312
qreal QFontEngineFT::underlinePosition() const
 
1313
{
 
1314
    return underline_position;
 
1315
}
 
1316
 
 
1317
 
 
1318
QOpenType *QFontEngineFT::openType() const
 
1319
{
 
1320
    if (_openType)
 
1321
         return _openType;
 
1322
 
 
1323
    FT_Face face = lockFace();
 
1324
    if (!face || !FT_IS_SFNT(face)) {
 
1325
        unlockFace();
 
1326
        return 0;
 
1327
    }
 
1328
 
 
1329
    _openType = new QOpenType(const_cast<QFontEngineFT *>(this), face);
 
1330
    unlockFace();
 
1331
    return _openType;
 
1332
}
 
1333
 
 
1334
#endif // QT_NO_FONTCONFIG