1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40
****************************************************************************/
42
#include "qfontengine_qpa_p.h"
44
#include <QtCore/QFile>
45
#include <QtCore/QFileInfo>
46
#include <QtCore/QDir>
47
#include <QtCore/QBuffer>
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>
56
//#define DEBUG_HEADER
57
//#define DEBUG_FONTENGINE
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
84
#if defined(DEBUG_HEADER)
85
# define DEBUG_VERIFY qDebug
87
# define DEBUG_VERIFY if (0) qDebug
90
#define READ_VERIFY(type, variable) \
91
if (tagPtr + sizeof(type) > endPtr) { \
92
DEBUG_VERIFY() << "read verify failed in line" << __LINE__; \
95
variable = qFromBigEndian<type>(tagPtr); \
96
DEBUG_VERIFY() << "read value" << variable << "of type " #type; \
97
tagPtr += sizeof(type)
100
T readValue(const uchar *&data)
102
T value = qFromBigEndian<T>(data);
107
#define VERIFY(condition) \
108
if (!(condition)) { \
109
DEBUG_VERIFY() << "condition " #condition " failed in line" << __LINE__; \
113
#define VERIFY_TAG(condition) \
114
if (!(condition)) { \
115
DEBUG_VERIFY() << "verifying tag condition " #condition " failed in line" << __LINE__ << "with tag" << tag; \
119
static inline const uchar *verifyTag(const uchar *tagPtr, const uchar *endPtr)
122
READ_VERIFY(quint16, tag);
123
READ_VERIFY(quint16, length);
124
if (tag == QFontEngineQPA::Tag_EndOfHeader)
126
if (tag < QFontEngineQPA::NumTags) {
127
switch (tagTypes[tag]) {
128
case QFontEngineQPA::BitFieldType:
129
case QFontEngineQPA::StringType:
130
// can't do anything...
132
case QFontEngineQPA::UInt32Type:
133
VERIFY_TAG(length == sizeof(quint32));
135
case QFontEngineQPA::FixedType:
136
VERIFY_TAG(length == sizeof(quint32));
138
case QFontEngineQPA::UInt8Type:
139
VERIFY_TAG(length == sizeof(quint8));
142
#if defined(DEBUG_HEADER)
144
qDebug() << "tag data" << hex << *tagPtr;
145
else if (length == 4)
146
qDebug() << "tag data" << hex << tagPtr[0] << tagPtr[1] << tagPtr[2] << tagPtr[3];
149
return tagPtr + length;
152
const QFontEngineQPA::Glyph *QFontEngineQPA::findGlyph(glyph_t g) const
154
if (!g || g >= glyphMapEntries)
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)
161
#if defined(DEBUG_FONTENGINE)
162
qDebug() << "glyph" << g << "outside of glyphData, remapping font file";
164
if (glyphPos > glyphDataSize)
167
return reinterpret_cast<const Glyph *>(fontData + glyphDataOffset + glyphPos);
170
bool QFontEngineQPA::verifyHeader(const uchar *data, int size)
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')
180
VERIFY(header->majorVersion <= CurrentMajorVersion);
181
const quint16 dataSize = qFromBigEndian<quint16>(header->dataSize);
182
VERIFY(size >= int(sizeof(Header)) + dataSize);
184
const uchar *tagPtr = data + sizeof(Header);
185
const uchar *tagEndPtr = tagPtr + dataSize;
186
while (tagPtr < tagEndPtr - 3) {
187
tagPtr = verifyTag(tagPtr, tagEndPtr);
191
VERIFY(tagPtr <= tagEndPtr);
195
QVariant QFontEngineQPA::extractHeaderField(const uchar *data, HeaderTag requestedTag)
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]) {
206
return QVariant(QString::fromUtf8(reinterpret_cast<const char *>(tagPtr), length));
208
return QVariant(readValue<quint32>(tagPtr));
210
return QVariant(uint(*tagPtr));
212
return QVariant(QFixed::fromFixed(readValue<quint32>(tagPtr)).toReal());
214
return QVariant(QByteArray(reinterpret_cast<const char *>(tagPtr), length));
217
} else if (tag == Tag_EndOfHeader) {
228
static inline unsigned int getChar(const QChar *str, int &i, const int len)
230
uint ucs4 = str[i].unicode();
231
if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
233
ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
238
QFontEngineQPA::QFontEngineQPA(const QFontDef &def, const QByteArray &data)
239
: fontData(reinterpret_cast<const uchar *>(data.constData())), dataSize(data.size())
250
kerning_pairs_loaded = false;
253
#if defined(DEBUG_FONTENGINE)
254
qDebug() << "QFontEngineQPA::QFontEngineQPA( fd =" << fd << ", renderingFontEngine =" << renderingFontEngine << ')';
257
if (!verifyHeader(fontData, dataSize)) {
258
#if defined(DEBUG_FONTENGINE)
259
qDebug() << "verifyHeader failed!";
264
const Header *header = reinterpret_cast<const Header *>(fontData);
266
readOnly = (header->lock == 0xffffffff);
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);
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;
286
imgData += blockSize;
289
face_id.filename = QFile::encodeName(extractHeaderField(fontData, Tag_FileName).toString());
290
face_id.index = extractHeaderField(fontData, Tag_FileIndex).toInt();
294
int tableSize = cmapSize;
295
const uchar *cmapPtr = getCMap(fontData + cmapOffset, tableSize, &symbol, &cmapSize);
297
cmapOffset = cmapPtr - fontData;
300
} else if (externalCMap) {
301
int tableSize = cmapSize;
302
externalCMap = getCMap(externalCMap, tableSize, &symbol, &cmapSize);
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)
312
if (glyphDataPos >= glyphDataSize) {
321
#if defined(DEBUG_FONTENGINE)
323
qDebug() << "fontData" << fontData << "dataSize" << dataSize
324
<< "externalCMap" << externalCMap << "cmapOffset" << cmapOffset
325
<< "glyphMapOffset" << glyphMapOffset << "glyphDataOffset" << glyphDataOffset
326
<< "fd" << fd << "glyphDataSize" << glyphDataSize;
330
QFontEngineQPA::~QFontEngineQPA()
334
bool QFontEngineQPA::getSfntTableData(uint tag, uchar *buffer, uint *length) const
342
bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
344
if (*nglyphs < len) {
349
#if defined(DEBUG_FONTENGINE)
350
QSet<QChar> seenGlyphs;
353
const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
355
bool mirrored = flags & QFontEngine::RightToLeft;
358
for (int i = 0; i < len; ++i) {
359
unsigned int uc = getChar(str, i, len);
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);
368
for (int i = 0; i < len; ++i) {
369
unsigned int uc = getChar(str, i, len);
371
uc = QChar::mirroredChar(uc);
372
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
373
#if 0 && defined(DEBUG_FONTENGINE)
375
if (!findGlyph(glyphs[glyph_pos].glyph) && !seenGlyphs.contains(c))
376
qDebug() << "glyph for character" << c << '/' << hex << uc << "is" << dec << glyphs[glyph_pos].glyph;
378
seenGlyphs.insert(c);
384
*nglyphs = glyph_pos;
385
glyphs->numGlyphs = glyph_pos;
387
if (!(flags & GlyphIndicesOnly))
388
recalcAdvances(glyphs, flags);
393
void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
395
for (int i = 0; i < glyphs->numGlyphs; ++i) {
396
const Glyph *g = findGlyph(glyphs->glyphs[i]);
398
glyphs->glyphs[i] = 0;
401
glyphs->advances_x[i] = g->advance;
402
glyphs->advances_y[i] = 0;
406
QImage QFontEngineQPA::alphaMapForGlyph(glyph_t g)
408
const Glyph *glyph = findGlyph(g);
412
const uchar *bits = ((const uchar *) glyph) + sizeof(Glyph);
414
QImage image(bits,glyph->width, glyph->height, glyph->bytesPerLine, QImage::Format_Indexed8);
419
void QFontEngineQPA::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
421
addBitmapFontToPath(x, y, glyphs, path, flags);
424
glyph_metrics_t QFontEngineQPA::boundingBox(const QGlyphLayout &glyphs)
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;
433
for (int i = 0; i < glyphs.numGlyphs; i++) {
434
const Glyph *g = findGlyph(glyphs.glyphs[i]);
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;
446
overall.height = qMax(overall.height, ymax - overall.y);
447
overall.width = xmax - overall.x;
452
glyph_metrics_t QFontEngineQPA::boundingBox(glyph_t glyph)
454
glyph_metrics_t overall;
455
const Glyph *g = findGlyph(glyph);
460
overall.width = g->width;
461
overall.height = g->height;
462
overall.xoff = g->advance;
466
QFixed QFontEngineQPA::ascent() const
468
return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value<qreal>());
471
QFixed QFontEngineQPA::descent() const
473
return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value<qreal>());
476
QFixed QFontEngineQPA::leading() const
478
return QFixed::fromReal(extractHeaderField(fontData, Tag_Leading).value<qreal>());
481
qreal QFontEngineQPA::maxCharWidth() const
483
return extractHeaderField(fontData, Tag_MaxCharWidth).value<qreal>();
486
qreal QFontEngineQPA::minLeftBearing() const
488
return extractHeaderField(fontData, Tag_MinLeftBearing).value<qreal>();
491
qreal QFontEngineQPA::minRightBearing() const
493
return extractHeaderField(fontData, Tag_MinRightBearing).value<qreal>();
496
QFixed QFontEngineQPA::underlinePosition() const
498
return QFixed::fromReal(extractHeaderField(fontData, Tag_UnderlinePosition).value<qreal>());
501
QFixed QFontEngineQPA::lineThickness() const
503
return QFixed::fromReal(extractHeaderField(fontData, Tag_LineThickness).value<qreal>());
506
QFontEngine::Type QFontEngineQPA::type() const
508
return QFontEngine::QPF2;
511
bool QFontEngineQPA::canRender(const QChar *string, int len)
513
const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
516
for (int i = 0; i < len; ++i) {
517
unsigned int uc = getChar(string, i, len);
518
glyph_t g = getTrueTypeGlyphIndex(cmap, uc);
520
g = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
525
for (int i = 0; i < len; ++i) {
526
unsigned int uc = getChar(string, i, len);
527
if (!getTrueTypeGlyphIndex(cmap, uc))
534
bool QFontEngineQPA::isValid() const
536
return fontData && dataSize && (cmapOffset || externalCMap)
537
&& glyphMapOffset && glyphDataOffset && glyphDataSize > 0;
540
void QPAGenerator::generate()
544
writeBlock(QFontEngineQPA::GlyphBlock, QByteArray());
546
dev->seek(4); // position of header.lock
550
void QPAGenerator::writeHeader()
552
QFontEngineQPA::Header header;
554
header.magic[0] = 'Q';
555
header.magic[1] = 'P';
556
header.magic[2] = 'F';
557
header.magic[3] = '2';
559
header.majorVersion = QFontEngineQPA::CurrentMajorVersion;
560
header.minorVersion = QFontEngineQPA::CurrentMinorVersion;
562
dev->write((const char *)&header, sizeof(header));
564
writeTaggedString(QFontEngineQPA::Tag_FontName, fe->fontDef.family.toUtf8());
566
QFontEngine::FaceId face = fe->faceId();
567
writeTaggedString(QFontEngineQPA::Tag_FileName, face.filename);
568
writeTaggedUInt32(QFontEngineQPA::Tag_FileIndex, face.index);
573
bool ok = fe->getSfntTableData(MAKE_TAG('h', 'e', 'a', 'd'), data, &len);
575
const quint32 revision = qFromBigEndian<quint32>(data);
576
writeTaggedUInt32(QFontEngineQPA::Tag_FontRevision, revision);
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);
594
writeTaggedUInt8(QFontEngineQPA::Tag_GlyphFormat, QFontEngineQPA::AlphamapGlyphs);
596
writeTaggedString(QFontEngineQPA::Tag_EndOfHeader, QByteArray());
599
const quint64 size = dev->pos();
600
header.dataSize = qToBigEndian<quint16>(size - sizeof(header));
602
dev->write((const char *)&header, sizeof(header));
606
void QPAGenerator::writeGMap()
608
const quint16 glyphCount = fe->glyphCount();
610
writeUInt16(QFontEngineQPA::GMapBlock);
611
writeUInt16(0); // padding
612
writeUInt32(glyphCount * 4);
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);
622
void QPAGenerator::writeBlock(QFontEngineQPA::BlockTag tag, const QByteArray &data)
625
writeUInt16(0); // padding
626
const int padSize = ((data.size() + 3) / 4) * 4 - data.size();
627
writeUInt32(data.size() + padSize);
629
for (int i = 0; i < padSize; ++i)
633
void QPAGenerator::writeTaggedString(QFontEngineQPA::HeaderTag tag, const QByteArray &string)
636
writeUInt16(string.length());
640
void QPAGenerator::writeTaggedUInt32(QFontEngineQPA::HeaderTag tag, quint32 value)
643
writeUInt16(sizeof(value));
647
void QPAGenerator::writeTaggedUInt8(QFontEngineQPA::HeaderTag tag, quint8 value)
650
writeUInt16(sizeof(value));
654
void QPAGenerator::writeTaggedQFixed(QFontEngineQPA::HeaderTag tag, QFixed value)
657
writeUInt16(sizeof(quint32));
658
writeUInt32(value.value());
663
Creates a new multi QPA engine.
665
This function takes ownership of the QFontEngine, increasing it's refcount.
667
QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script, const QStringList &fallbacks)
668
: QFontEngineMulti(fallbacks.size() + 1),
669
fallbackFamilies(fallbacks), script(_script)
670
, fallbacksQueried(true)
675
QFontEngineMultiQPA::QFontEngineMultiQPA(QFontEngine *fe, int _script)
676
: QFontEngineMulti(2)
678
, fallbacksQueried(false)
680
fallbackFamilies << QString();
684
void QFontEngineMultiQPA::init(QFontEngine *fe)
686
Q_ASSERT(fe && fe->type() != QFontEngine::Multi);
689
fontDef = engines[0]->fontDef;
690
setObjectName(QStringLiteral("QFontEngineMultiQPA"));
693
void QFontEngineMultiQPA::loadEngine(int at)
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,
703
request, /*multi = */false);
704
Q_ASSERT(engines[at]);
705
engines[at]->ref.ref();
706
engines[at]->fontDef = request;
708
void QFontEngineMultiQPA::ensureFallbackFamiliesQueried()
710
if (fallbacksQueried)
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);
717
void QFontEngineMultiQPA::setFallbackFamiliesList(const QStringList &fallbacks)
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);
726
// Turns out we lied about having any fallback at all.
727
fallbackFamilies << fe->fontDef.family;
731
fallbacksQueried = true;
735
This is used indirectly by QtWebKit when using QTextLayout::setRawFont
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.
742
QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
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());
765
engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QUnicodeTables::Script(script));
766
QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);