~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the QtGui module of the Qt Toolkit.
 
7
**
 
8
** $QT_BEGIN_LICENSE:LGPL$
 
9
** Commercial License Usage
 
10
** Licensees holding valid commercial Qt licenses may use this file in
 
11
** accordance with the commercial license agreement provided with the
 
12
** Software or, alternatively, in accordance with the terms contained in
 
13
** a written agreement between you and Digia.  For licensing terms and
 
14
** conditions see http://qt.digia.com/licensing.  For further information
 
15
** use the contact form at http://qt.digia.com/contact-us.
 
16
**
 
17
** GNU Lesser General Public License Usage
 
18
** Alternatively, this file may be used under the terms of the GNU Lesser
 
19
** General Public License version 2.1 as published by the Free Software
 
20
** Foundation and appearing in the file LICENSE.LGPL included in the
 
21
** packaging of this file.  Please review the following information to
 
22
** ensure the GNU Lesser General Public License version 2.1 requirements
 
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 
24
**
 
25
** In addition, as a special exception, Digia gives you certain additional
 
26
** rights.  These rights are described in the Digia Qt LGPL Exception
 
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 
28
**
 
29
** GNU General Public License Usage
 
30
** Alternatively, this file may be used under the terms of the GNU
 
31
** General Public License version 3.0 as published by the Free Software
 
32
** Foundation and appearing in the file LICENSE.GPL included in the
 
33
** packaging of this file.  Please review the following information to
 
34
** ensure the GNU General Public License version 3.0 requirements will be
 
35
** met: http://www.gnu.org/copyleft/gpl.html.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include "qfontengine_qpa_p.h"
 
43
 
 
44
#include <QtCore/QFile>
 
45
#include <QtCore/QFileInfo>
 
46
#include <QtCore/QDir>
 
47
#include <QtCore/QBuffer>
 
48
 
 
49
#include <QtGui/private/qpaintengine_raster_p.h>
 
50
#include <QtGui/private/qguiapplication_p.h>
 
51
#include <qpa/qplatformfontdatabase.h>
 
52
#include <qpa/qplatformintegration.h>
 
53
 
 
54
QT_BEGIN_NAMESPACE
 
55
 
 
56
//#define DEBUG_HEADER
 
57
//#define DEBUG_FONTENGINE
 
58
 
 
59
static QFontEngineQPA::TagType tagTypes[QFontEngineQPA::NumTags] = {
 
60
    QFontEngineQPA::StringType, // FontName
 
61
    QFontEngineQPA::StringType, // FileName
 
62
    QFontEngineQPA::UInt32Type, // FileIndex
 
63
    QFontEngineQPA::UInt32Type, // FontRevision
 
64
    QFontEngineQPA::StringType, // FreeText
 
65
    QFontEngineQPA::FixedType,  // Ascent
 
66
    QFontEngineQPA::FixedType,  // Descent
 
67
    QFontEngineQPA::FixedType,  // Leading
 
68
    QFontEngineQPA::FixedType,  // XHeight
 
69
    QFontEngineQPA::FixedType,  // AverageCharWidth
 
70
    QFontEngineQPA::FixedType,  // MaxCharWidth
 
71
    QFontEngineQPA::FixedType,  // LineThickness
 
72
    QFontEngineQPA::FixedType,  // MinLeftBearing
 
73
    QFontEngineQPA::FixedType,  // MinRightBearing
 
74
    QFontEngineQPA::FixedType,  // UnderlinePosition
 
75
    QFontEngineQPA::UInt8Type,  // GlyphFormat
 
76
    QFontEngineQPA::UInt8Type,  // PixelSize
 
77
    QFontEngineQPA::UInt8Type,  // Weight
 
78
    QFontEngineQPA::UInt8Type,  // Style
 
79
    QFontEngineQPA::StringType, // EndOfHeader
 
80
    QFontEngineQPA::BitFieldType// WritingSystems
 
81
};
 
82
 
 
83
 
 
84
#if defined(DEBUG_HEADER)
 
85
# define DEBUG_VERIFY qDebug
 
86
#else
 
87
# define DEBUG_VERIFY if (0) qDebug
 
88
#endif
 
89
 
 
90
#define READ_VERIFY(type, variable) \
 
91
    if (tagPtr + sizeof(type) > endPtr) { \
 
92
        DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
 
93
        return 0; \
 
94
    } \
 
95
    variable = qFromBigEndian<type>(tagPtr); \
 
96
    DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
 
97
    tagPtr += sizeof(type)
 
98
 
 
99
template <typename T>
 
100
T readValue(const uchar *&data)
 
101
{
 
102
    T value = qFromBigEndian<T>(data);
 
103
    data += sizeof(T);
 
104
    return value;
 
105
}
 
106
 
 
107
#define VERIFY(condition) \
 
108
    if (!(condition)) { \
 
109
        DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
 
110
        return 0; \
 
111
    }
 
112
 
 
113
#define VERIFY_TAG(condition) \
 
114
    if (!(condition)) { \
 
115
        DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
 
116
        return 0; \
 
117
    }
 
118
 
 
119
static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
 
120
{
 
121
    quint16 tag, length;
 
122
    READ_VERIFY(quint16, tag);
 
123
    READ_VERIFY(quint16, length);
 
124
    if (tag == QFontEngineQPA::Tag_EndOfHeader)
 
125
        return endPtr;
 
126
    if (tag < QFontEngineQPA::NumTags) {
 
127
        switch (tagTypes[tag]) {
 
128
            case QFontEngineQPA::BitFieldType:
 
129
            case QFontEngineQPA::StringType:
 
130
                // can't do anything...
 
131
                break;
 
132
            case QFontEngineQPA::UInt32Type:
 
133
                VERIFY_TAG(length == sizeof(quint32));
 
134
                break;
 
135
            case QFontEngineQPA::FixedType:
 
136
                VERIFY_TAG(length == sizeof(quint32));
 
137
                break;
 
138
            case QFontEngineQPA::UInt8Type:
 
139
                VERIFY_TAG(length == sizeof(quint8));
 
140
                break;
 
141
        }
 
142
#if defined(DEBUG_HEADER)
 
143
        if (length == 1)
 
144
            qDebug() << "tag data" << hex << *tagPtr;
 
145
        else if (length == 4)
 
146
            qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
 
147
#endif
 
148
    }
 
149
    return tagPtr + length;
 
150
}
 
151
 
 
152
const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
 
153
{
 
154
    if (!g || g >= glyphMapEntries)
 
155
        return 0;
 
156
    const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
 
157
    quint32 glyphPos = qFromBigEndian<quint32>(gmapPtr[g]);
 
158
    if (glyphPos > glyphDataSize) {
 
159
        if (glyphPos == 0xffffffff)
 
160
            return 0;
 
161
#if defined(DEBUG_FONTENGINE)
 
162
        qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
 
163
#endif
 
164
        if (glyphPos > glyphDataSize)
 
165
            return 0;
 
166
    }
 
167
    return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
 
168
}
 
169
 
 
170
bool QFontEngineQPA::verifyHeader(const uchar *data, int size)
 
171
{
 
172
    VERIFY(size >= int(sizeof(Header)));
 
173
    const Header *header = reinterpret_cast<const Header *>(data);
 
174
    if (header->magic[0] != 'Q'
 
175
        || header->magic[1] != 'P'
 
176
        || header->magic[2] != 'F'
 
177
        || header->magic[3] != '2')
 
178
        return false;
 
179
 
 
180
    VERIFY(header->majorVersion <= CurrentMajorVersion);
 
181
    const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
 
182
    VERIFY(size >= int(sizeof(Header)) + dataSize);
 
183
 
 
184
    const uchar *tagPtr = data + sizeof(Header);
 
185
    const uchar *tagEndPtr = tagPtr + dataSize;
 
186
    while (tagPtr < tagEndPtr - 3) {
 
187
        tagPtr = verifyTag(tagPtr, tagEndPtr);
 
188
        VERIFY(tagPtr);
 
189
    }
 
190
 
 
191
    VERIFY(tagPtr <= tagEndPtr);
 
192
    return true;
 
193
}
 
194
 
 
195
QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag)
 
196
{
 
197
    const Header *header = reinterpret_cast<const Header *>(data);
 
198
    const uchar *tagPtr = data + sizeof(Header);
 
199
    const uchar *endPtr = tagPtr + qFromBigEndian<quint16>(header->dataSize);
 
200
    while (tagPtr < endPtr - 3) {
 
201
        quint16 tag = readValue<quint16>(tagPtr);
 
202
        quint16 length = readValue<quint16>(tagPtr);
 
203
        if (tag == requestedTag) {
 
204
            switch (tagTypes[requestedTag]) {
 
205
                case StringType:
 
206
                    return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
 
207
                case UInt32Type:
 
208
                    return QVariant(readValue<quint32>(tagPtr));
 
209
                case UInt8Type:
 
210
                    return QVariant(uint(*tagPtr));
 
211
                case FixedType:
 
212
                    return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
 
213
                case BitFieldType:
 
214
                    return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
 
215
            }
 
216
            return QVariant();
 
217
        } else if (tag == Tag_EndOfHeader) {
 
218
            break;
 
219
        }
 
220
        tagPtr += length;
 
221
    }
 
222
 
 
223
    return QVariant();
 
224
}
 
225
 
 
226
 
 
227
 
 
228
static inline unsigned int getChar(const QChar *str, int &i, const int len)
 
229
{
 
230
    uint ucs4 = str[i].unicode();
 
231
    if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
 
232
        ++i;
 
233
        ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
 
234
    }
 
235
    return ucs4;
 
236
}
 
237
 
 
238
QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
 
239
    : fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
 
240
{
 
241
    fontDef = def;
 
242
    cache_cost = 100;
 
243
    externalCMap = 0;
 
244
    cmapOffset = 0;
 
245
    cmapSize = 0;
 
246
    glyphMapOffset = 0;
 
247
    glyphMapEntries = 0;
 
248
    glyphDataOffset = 0;
 
249
    glyphDataSize = 0;
 
250
    kerning_pairs_loaded = false;
 
251
    readOnly = true;
 
252
 
 
253
#if defined(DEBUG_FONTENGINE)
 
254
    qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
 
255
#endif
 
256
 
 
257
    if (!verifyHeader(fontData, dataSize)) {
 
258
#if defined(DEBUG_FONTENGINE)
 
259
        qDebug() << "verifyHeader failed!";
 
260
#endif
 
261
        return;
 
262
    }
 
263
 
 
264
    const Header *header = reinterpret_cast<const Header *>(fontData);
 
265
 
 
266
    readOnly = (header->lock == 0xffffffff);
 
267
 
 
268
    const uchar *imgData = fontData + sizeof(Header) + qFromBigEndian<quint16>(header->dataSize);
 
269
    const uchar *endPtr = fontData + dataSize;
 
270
    while (imgData <= endPtr - 8) {
 
271
        quint16 blockTag = readValue<quint16>(imgData);
 
272
        imgData += 2; // skip padding
 
273
        quint32 blockSize = readValue<quint32>(imgData);
 
274
 
 
275
        if (blockTag == CMapBlock) {
 
276
            cmapOffset = imgData - fontData;
 
277
            cmapSize = blockSize;
 
278
        } else if (blockTag == GMapBlock) {
 
279
            glyphMapOffset = imgData - fontData;
 
280
            glyphMapEntries = blockSize / 4;
 
281
        } else if (blockTag == GlyphBlock) {
 
282
            glyphDataOffset = imgData - fontData;
 
283
            glyphDataSize = blockSize;
 
284
        }
 
285
 
 
286
        imgData += blockSize;
 
287
    }
 
288
 
 
289
    face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
 
290
    face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
 
291
 
 
292
    // get the real cmap
 
293
    if (cmapOffset) {
 
294
        int tableSize = cmapSize;
 
295
        const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
 
296
        if (cmapPtr)
 
297
            cmapOffset = cmapPtr - fontData;
 
298
        else
 
299
            cmapOffset = 0;
 
300
    } else if (externalCMap) {
 
301
        int tableSize = cmapSize;
 
302
        externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
 
303
    }
 
304
 
 
305
    // verify all the positions in the glyphMap
 
306
    if (glyphMapOffset) {
 
307
        const quint32 *gmapPtr = reinterpret_cast<const quint32 *>(fontData + glyphMapOffset);
 
308
        for (uint i = 0; i < glyphMapEntries; ++i) {
 
309
            quint32 glyphDataPos = qFromBigEndian<quint32>(gmapPtr[i]);
 
310
            if (glyphDataPos == 0xffffffff)
 
311
                continue;
 
312
            if (glyphDataPos >= glyphDataSize) {
 
313
                // error
 
314
                glyphMapOffset = 0;
 
315
                glyphMapEntries = 0;
 
316
                break;
 
317
            }
 
318
        }
 
319
    }
 
320
 
 
321
#if defined(DEBUG_FONTENGINE)
 
322
    if (!isValid())
 
323
        qDebug() << "fontData" <<  fontData << "dataSize" << dataSize
 
324
                 << "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
 
325
                 << "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
 
326
                 << "fd" << fd << "glyphDataSize" << glyphDataSize;
 
327
#endif
 
328
}
 
329
 
 
330
QFontEngineQPA::~QFontEngineQPA()
 
331
{
 
332
}
 
333
 
 
334
bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
 
335
{
 
336
    Q_UNUSED(tag);
 
337
    Q_UNUSED(buffer);
 
338
    *length = 0;
 
339
    return false;
 
340
}
 
341
 
 
342
bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
 
343
{
 
344
    if (*nglyphs < len) {
 
345
        *nglyphs = len;
 
346
        return false;
 
347
    }
 
348
 
 
349
#if defined(DEBUG_FONTENGINE)
 
350
    QSet<QChar> seenGlyphs;
 
351
#endif
 
352
 
 
353
    const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
 
354
 
 
355
    bool mirrored = flags & QFontEngine::RightToLeft;
 
356
    int glyph_pos = 0;
 
357
    if (symbol) {
 
358
        for (int i = 0; i < len; ++i) {
 
359
            unsigned int uc = getChar(str, i, len);
 
360
            if (mirrored)
 
361
                uc = QChar::mirroredChar(uc);
 
362
            glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
 
363
            if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
 
364
                glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
 
365
            ++glyph_pos;
 
366
        }
 
367
    } else {
 
368
        for (int i = 0; i < len; ++i) {
 
369
            unsigned int uc = getChar(str, i, len);
 
370
            if (mirrored)
 
371
                uc = QChar::mirroredChar(uc);
 
372
            glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
 
373
#if 0 && defined(DEBUG_FONTENGINE)
 
374
            QChar c(uc);
 
375
            if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
 
376
                qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
 
377
 
 
378
            seenGlyphs.insert(c);
 
379
#endif
 
380
            ++glyph_pos;
 
381
        }
 
382
    }
 
383
 
 
384
    *nglyphs = glyph_pos;
 
385
    glyphs->numGlyphs = glyph_pos;
 
386
 
 
387
    if (!(flags & GlyphIndicesOnly))
 
388
        recalcAdvances(glyphs, flags);
 
389
 
 
390
    return true;
 
391
}
 
392
 
 
393
void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
 
394
{
 
395
    for (int i = 0; i < glyphs->numGlyphs; ++i) {
 
396
        const Glyph *g = findGlyph(glyphs->glyphs[i]);
 
397
        if (!g) {
 
398
            glyphs->glyphs[i] = 0;
 
399
            continue;
 
400
        }
 
401
        glyphs->advances_x[i] = g->advance;
 
402
        glyphs->advances_y[i] = 0;
 
403
    }
 
404
}
 
405
 
 
406
QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
 
407
{
 
408
    const Glyph *glyph = findGlyph(g);
 
409
    if (!glyph)
 
410
        return QImage();
 
411
 
 
412
    const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
 
413
 
 
414
    QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
 
415
 
 
416
    return image;
 
417
}
 
418
 
 
419
void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
 
420
{
 
421
    addBitmapFontToPath(x, y, glyphs, path, flags);
 
422
}
 
423
 
 
424
glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
 
425
{
 
426
    glyph_metrics_t overall;
 
427
    // initialize with line height, we get the same behaviour on all platforms
 
428
    overall.y = -ascent();
 
429
    overall.height = ascent() + descent() + 1;
 
430
 
 
431
    QFixed ymax = 0;
 
432
    QFixed xmax = 0;
 
433
    for (int i = 0; i < glyphs.numGlyphs; i++) {
 
434
        const Glyph *g = findGlyph(glyphs.glyphs[i]);
 
435
        if (!g)
 
436
            continue;
 
437
 
 
438
        QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
 
439
        QFixed y = overall.yoff + glyphs.offsets[i].y + g->y;
 
440
        overall.x = qMin(overall.x, x);
 
441
        overall.y = qMin(overall.y, y);
 
442
        xmax = qMax(xmax, x + g->width);
 
443
        ymax = qMax(ymax, y + g->height);
 
444
        overall.xoff += g->advance;
 
445
    }
 
446
    overall.height = qMax(overall.height, ymax - overall.y);
 
447
    overall.width = xmax - overall.x;
 
448
 
 
449
    return overall;
 
450
}
 
451
 
 
452
glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
 
453
{
 
454
    glyph_metrics_t overall;
 
455
    const Glyph *g = findGlyph(glyph);
 
456
    if (!g)
 
457
        return overall;
 
458
    overall.x = g->x;
 
459
    overall.y = g->y;
 
460
    overall.width = g->width;
 
461
    overall.height = g->height;
 
462
    overall.xoff = g->advance;
 
463
    return overall;
 
464
}
 
465
 
 
466
QFixed QFontEngineQPA::ascent() const
 
467
{
 
468
    return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
 
469
}
 
470
 
 
471
QFixed QFontEngineQPA::descent() const
 
472
{
 
473
    return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
 
474
}
 
475
 
 
476
QFixed QFontEngineQPA::leading() const
 
477
{
 
478
    return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
 
479
}
 
480
 
 
481
qreal QFontEngineQPA::maxCharWidth() const
 
482
{
 
483
    return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
 
484
}
 
485
 
 
486
qreal QFontEngineQPA::minLeftBearing() const
 
487
{
 
488
    return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
 
489
}
 
490
 
 
491
qreal QFontEngineQPA::minRightBearing() const
 
492
{
 
493
    return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
 
494
}
 
495
 
 
496
QFixed QFontEngineQPA::underlinePosition() const
 
497
{
 
498
    return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
 
499
}
 
500
 
 
501
QFixed QFontEngineQPA::lineThickness() const
 
502
{
 
503
    return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
 
504
}
 
505
 
 
506
QFontEngine::Type QFontEngineQPA::type() const
 
507
{
 
508
    return QFontEngine::QPF2;
 
509
}
 
510
 
 
511
bool QFontEngineQPA::canRender(const QChar *string, int len)
 
512
{
 
513
    const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
 
514
 
 
515
    if (symbol) {
 
516
        for (int i = 0; i < len; ++i) {
 
517
            unsigned int uc = getChar(string, i, len);
 
518
            glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
 
519
            if(!g && uc < 0x100)
 
520
                g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
 
521
            if (!g)
 
522
                return false;
 
523
        }
 
524
    } else {
 
525
        for (int i = 0; i < len; ++i) {
 
526
            unsigned int uc = getChar(string, i, len);
 
527
            if (!getTrueTypeGlyphIndex(cmap, uc))
 
528
                return false;
 
529
        }
 
530
    }
 
531
    return true;
 
532
}
 
533
 
 
534
bool QFontEngineQPA::isValid() const
 
535
{
 
536
    return fontData && dataSize && (cmapOffset || externalCMap)
 
537
           && glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
 
538
}
 
539
 
 
540
void QPAGenerator::generate()
 
541
{
 
542
    writeHeader();
 
543
    writeGMap();
 
544
    writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
 
545
 
 
546
    dev->seek(4); // position of header.lock
 
547
    writeUInt32(0);
 
548
}
 
549
 
 
550
void QPAGenerator::writeHeader()
 
551
{
 
552
    QFontEngineQPA::Header header;
 
553
 
 
554
    header.magic[0] = 'Q';
 
555
    header.magic[1] = 'P';
 
556
    header.magic[2] = 'F';
 
557
    header.magic[3] = '2';
 
558
    header.lock = 1;
 
559
    header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
 
560
    header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
 
561
    header.dataSize = 0;
 
562
    dev->write((const char *)&header, sizeof(header));
 
563
 
 
564
    writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
 
565
 
 
566
    QFontEngine::FaceId face = fe->faceId();
 
567
    writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
 
568
    writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
 
569
 
 
570
    {
 
571
        uchar data[4];
 
572
        uint len = 4;
 
573
        bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
 
574
        if (ok) {
 
575
            const quint32 revision = qFromBigEndian<quint32>(data);
 
576
            writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
 
577
        }
 
578
    }
 
579
 
 
580
    writeTaggedQFixed(QFontEngineQPA::Tag_Ascent, fe->ascent());
 
581
    writeTaggedQFixed(QFontEngineQPA::Tag_Descent, fe->descent());
 
582
    writeTaggedQFixed(QFontEngineQPA::Tag_Leading, fe->leading());
 
583
    writeTaggedQFixed(QFontEngineQPA::Tag_XHeight, fe->xHeight());
 
584
    writeTaggedQFixed(QFontEngineQPA::Tag_AverageCharWidth, fe->averageCharWidth());
 
585
    writeTaggedQFixed(QFontEngineQPA::Tag_MaxCharWidth, QFixed::fromReal(fe->maxCharWidth()));
 
586
    writeTaggedQFixed(QFontEngineQPA::Tag_LineThickness, fe->lineThickness());
 
587
    writeTaggedQFixed(QFontEngineQPA::Tag_MinLeftBearing, QFixed::fromReal(fe->minLeftBearing()));
 
588
    writeTaggedQFixed(QFontEngineQPA::Tag_MinRightBearing, QFixed::fromReal(fe->minRightBearing()));
 
589
    writeTaggedQFixed(QFontEngineQPA::Tag_UnderlinePosition, fe->underlinePosition());
 
590
    writeTaggedUInt8(QFontEngineQPA::Tag_PixelSize, fe->fontDef.pixelSize);
 
591
    writeTaggedUInt8(QFontEngineQPA::Tag_Weight, fe->fontDef.weight);
 
592
    writeTaggedUInt8(QFontEngineQPA::Tag_Style, fe->fontDef.style);
 
593
 
 
594
    writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
 
595
 
 
596
    writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
 
597
    align4();
 
598
 
 
599
    const quint64 size = dev->pos();
 
600
    header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
 
601
    dev->seek(0);
 
602
    dev->write((const char *)&header, sizeof(header));
 
603
    dev->seek(size);
 
604
}
 
605
 
 
606
void QPAGenerator::writeGMap()
 
607
{
 
608
    const quint16 glyphCount = fe->glyphCount();
 
609
 
 
610
    writeUInt16(QFontEngineQPA::GMapBlock);
 
611
    writeUInt16(0); // padding
 
612
    writeUInt32(glyphCount * 4);
 
613
 
 
614
    QByteArray &buffer = dev->buffer();
 
615
    const int numBytes = glyphCount * sizeof(quint32);
 
616
    qint64 pos = buffer.size();
 
617
    buffer.resize(pos + numBytes);
 
618
    memset(buffer.data() + pos, 0xff, numBytes);
 
619
    dev->seek(pos + numBytes);
 
620
}
 
621
 
 
622
void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
 
623
{
 
624
    writeUInt16(tag);
 
625
    writeUInt16(0); // padding
 
626
    const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
 
627
    writeUInt32(data.size() + padSize);
 
628
    dev->write(data);
 
629
    for (int i = 0; i < padSize; ++i)
 
630
        writeUInt8(0);
 
631
}
 
632
 
 
633
void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
 
634
{
 
635
    writeUInt16(tag);
 
636
    writeUInt16(string.length());
 
637
    dev->write(string);
 
638
}
 
639
 
 
640
void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
 
641
{
 
642
    writeUInt16(tag);
 
643
    writeUInt16(sizeof(value));
 
644
    writeUInt32(value);
 
645
}
 
646
 
 
647
void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
 
648
{
 
649
    writeUInt16(tag);
 
650
    writeUInt16(sizeof(value));
 
651
    writeUInt8(value);
 
652
}
 
653
 
 
654
void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
 
655
{
 
656
    writeUInt16(tag);
 
657
    writeUInt16(sizeof(quint32));
 
658
    writeUInt32(value.value());
 
659
}
 
660
 
 
661
 
 
662
/*
 
663
    Creates a new multi QPA engine.
 
664
 
 
665
    This function takes ownership of the QFontEngine, increasing it's refcount.
 
666
*/
 
667
QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
 
668
    : QFontEngineMulti(fallbacks.size() + 1),
 
669
      fallbackFamilies(fallbacks), script(_script)
 
670
    , fallbacksQueried(true)
 
671
{
 
672
    init(fe);
 
673
}
 
674
 
 
675
QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script)
 
676
    : QFontEngineMulti(2)
 
677
    , script(_script)
 
678
    , fallbacksQueried(false)
 
679
{
 
680
    fallbackFamilies << QString();
 
681
    init(fe);
 
682
}
 
683
 
 
684
void QFontEngineMultiQPA::init(QFontEngine *fe)
 
685
{
 
686
    Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
 
687
    engines[0] = fe;
 
688
    fe->ref.ref();
 
689
    fontDef = engines[0]->fontDef;
 
690
    setObjectName(QStringLiteral("QFontEngineMultiQPA"));
 
691
}
 
692
 
 
693
void QFontEngineMultiQPA::loadEngine(int at)
 
694
{
 
695
    ensureFallbackFamiliesQueried();
 
696
    Q_ASSERT(at < engines.size());
 
697
    Q_ASSERT(engines.at(at) == 0);
 
698
    QFontDef request = fontDef;
 
699
    request.styleStrategy |= QFont::NoFontMerging;
 
700
    request.family = fallbackFamilies.at(at-1);
 
701
    engines[at] = QFontDatabase::findFont(script,
 
702
                                          /*fontprivate = */0,
 
703
                                          request, /*multi = */false);
 
704
    Q_ASSERT(engines[at]);
 
705
    engines[at]->ref.ref();
 
706
    engines[at]->fontDef = request;
 
707
}
 
708
void QFontEngineMultiQPA::ensureFallbackFamiliesQueried()
 
709
{
 
710
    if (fallbacksQueried)
 
711
        return;
 
712
    QStringList fallbacks = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fallbacksForFamily(engine(0)->fontDef.family, QFont::Style(engine(0)->fontDef.style)
 
713
                                                                                                                     , QFont::AnyStyle, QUnicodeTables::Script(script));
 
714
    setFallbackFamiliesList(fallbacks);
 
715
}
 
716
 
 
717
void QFontEngineMultiQPA::setFallbackFamiliesList(const QStringList &fallbacks)
 
718
{
 
719
    // Original FontEngine to restore after the fill.
 
720
    QFontEngine *fe = engines[0];
 
721
    fallbackFamilies = fallbacks;
 
722
    if (!fallbackFamilies.isEmpty()) {
 
723
        engines.fill(0, fallbackFamilies.size() + 1);
 
724
        engines[0] = fe;
 
725
    } else {
 
726
        // Turns out we lied about having any fallback at all.
 
727
        fallbackFamilies << fe->fontDef.family;
 
728
        engines[1] = fe;
 
729
        fe->ref.ref();
 
730
    }
 
731
    fallbacksQueried = true;
 
732
}
 
733
 
 
734
/*
 
735
  This is used indirectly by QtWebKit when using QTextLayout::setRawFont
 
736
 
 
737
  The purpose of this is to provide the necessary font fallbacks when drawing complex
 
738
  text. Since QtWebKit ends up repeatedly creating QTextLayout instances and passing them
 
739
  the same raw font over and over again, we want to cache the corresponding multi font engine
 
740
  as it may contain fallback font engines already.
 
741
*/
 
742
QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
 
743
{
 
744
    QFontEngine *engine = 0;
 
745
    QFontCache::Key key(fe->fontDef, script, /*multi = */true);
 
746
    QFontCache *fc = QFontCache::instance();
 
747
    //  We can't rely on the fontDef (and hence the cache Key)
 
748
    //  alone to distinguish webfonts, since these should not be
 
749
    //  accidentally shared, even if the resulting fontcache key
 
750
    //  is strictly identical. See:
 
751
    //   http://www.w3.org/TR/css3-fonts/#font-face-rule
 
752
    const bool faceIsLocal = !fe->faceId().filename.isEmpty();
 
753
    QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
 
754
            end = fc->engineCache.end();
 
755
    while (it != end && it.key() == key) {
 
756
        QFontEngineMulti *cachedEngine = qobject_cast<QFontEngineMulti *>(it.value().data);
 
757
        if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
 
758
            engine = cachedEngine;
 
759
            fc->updateHitCountAndTimeStamp(it.value());
 
760
            break;
 
761
        }
 
762
        it++;
 
763
    }
 
764
    if (!engine) {
 
765
        engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QUnicodeTables::Script(script));
 
766
        QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);
 
767
    }
 
768
    Q_ASSERT(engine);
 
769
    return engine;
 
770
}
 
771
 
 
772
QT_END_NAMESPACE