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;
730 fallbacksQueried = true;
734 This is used indirectly by QtWebKit when using QTextLayout::setRawFont
736 The purpose of this is to provide the necessary font fallbacks when drawing complex
737 text. Since QtWebKit ends up repeatedly creating QTextLayout instances and passing them
738 the same raw font over and over again, we want to cache the corresponding multi font engine
739 as it may contain fallback font engines already.
741 QFontEngine* QFontEngineMultiQPA::createMultiFontEngine(QFontEngine *fe, int script)
743 QFontEngine *engine = 0;
744 QFontCache::Key key(fe->fontDef, script, /*multi = */true);
745 QFontCache *fc = QFontCache::instance();
746 // We can't rely on the fontDef (and hence the cache Key)
747 // alone to distinguish webfonts, since these should not be
748 // accidentally shared, even if the resulting fontcache key
749 // is strictly identical. See:
750 // http://www.w3.org/TR/css3-fonts/#font-face-rule
751 const bool faceIsLocal = !fe->faceId().filename.isEmpty();
752 QFontCache::EngineCache::Iterator it = fc->engineCache.find(key),
753 end = fc->engineCache.end();
754 while (it != end && it.key() == key) {
755 QFontEngineMulti *cachedEngine = qobject_cast<QFontEngineMulti *>(it.value().data);
756 if (faceIsLocal || (cachedEngine && fe == cachedEngine->engine(0))) {
757 engine = cachedEngine;
758 fc->updateHitCountAndTimeStamp(it.value());
764 engine = QGuiApplicationPrivate::instance()->platformIntegration()->fontDatabase()->fontEngineMulti(fe, QUnicodeTables::Script(script));
765 QFontCache::instance()->insertEngine(key, engine, /* insertMulti */ !faceIsLocal);