1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qrawfont_p.h"
43 #include <private/qsystemlibrary_p.h>
45 #if !defined(QT_NO_DIRECTWRITE)
46 # include "qfontenginedirectwrite_p.h"
50 #if !defined(QT_NO_RAWFONT)
59 quint8 data[sizeof(T)];
64 for (int i=0; i<sizeof(T); ++i) {
65 littleEndian |= data[i] << ((sizeof(T) - i - 1) * 8);
71 BigEndian<T> &operator=(const T &t)
73 for (int i=0; i<sizeof(T); ++i) {
74 data[i] = ((t >> (sizeof(T) - i - 1) * 8) & 0xff);
83 // Common structure for all formats of the "name" table
86 BigEndian<quint16> format;
87 BigEndian<quint16> count;
88 BigEndian<quint16> stringOffset;
93 BigEndian<quint16> platformID;
94 BigEndian<quint16> encodingID;
95 BigEndian<quint16> languageID;
96 BigEndian<quint16> nameID;
97 BigEndian<quint16> length;
98 BigEndian<quint16> offset;
101 struct OffsetSubTable
103 BigEndian<quint32> scalerType;
104 BigEndian<quint16> numTables;
105 BigEndian<quint16> searchRange;
106 BigEndian<quint16> entrySelector;
107 BigEndian<quint16> rangeShift;
110 struct TableDirectory
112 BigEndian<quint32> identifier;
113 BigEndian<quint32> checkSum;
114 BigEndian<quint32> offset;
115 BigEndian<quint32> length;
120 BigEndian<quint16> version;
121 BigEndian<qint16> avgCharWidth;
122 BigEndian<quint16> weightClass;
123 BigEndian<quint16> widthClass;
124 BigEndian<quint16> type;
125 BigEndian<qint16> subscriptXSize;
126 BigEndian<qint16> subscriptYSize;
127 BigEndian<qint16> subscriptXOffset;
128 BigEndian<qint16> subscriptYOffset;
129 BigEndian<qint16> superscriptXSize;
130 BigEndian<qint16> superscriptYSize;
131 BigEndian<qint16> superscriptXOffset;
132 BigEndian<qint16> superscriptYOffset;
133 BigEndian<qint16> strikeOutSize;
134 BigEndian<qint16> strikeOutPosition;
135 BigEndian<qint16> familyClass;
137 BigEndian<quint32> unicodeRanges[4];
139 BigEndian<quint16> selection;
140 BigEndian<quint16> firstCharIndex;
141 BigEndian<quint16> lastCharIndex;
142 BigEndian<qint16> typoAscender;
143 BigEndian<qint16> typoDescender;
144 BigEndian<qint16> typoLineGap;
145 BigEndian<quint16> winAscent;
146 BigEndian<quint16> winDescent;
147 BigEndian<quint32> codepageRanges[2];
148 BigEndian<qint16> height;
149 BigEndian<qint16> capHeight;
150 BigEndian<quint16> defaultChar;
151 BigEndian<quint16> breakChar;
152 BigEndian<quint16> maxContext;
160 EmbeddedFont(const QByteArray &fontData);
162 QString changeFamilyName(const QString &newFamilyName);
163 QByteArray data() const { return m_fontData; }
164 TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
165 QString familyName(TableDirectory *nameTableDirectory = 0);
168 QByteArray m_fontData;
171 EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData)
175 TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
177 Q_ASSERT(tagName.size() == 4);
179 const BigEndian<quint32> *tagIdPtr =
180 reinterpret_cast<const BigEndian<quint32> *>(tagName.constData());
181 quint32 tagId = *tagIdPtr;
183 OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
184 TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
186 TableDirectory *nameTableDirectoryEntry = 0;
187 for (int i=0; i<offsetSubTable->numTables; ++i, ++tableDirectory) {
188 if (tableDirectory->identifier == tagId) {
189 nameTableDirectoryEntry = tableDirectory;
194 return nameTableDirectoryEntry;
197 QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
201 if (nameTableDirectoryEntry == 0)
202 nameTableDirectoryEntry = tableDirectoryEntry("name");
204 if (nameTableDirectoryEntry != 0) {
205 NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data()
206 + nameTableDirectoryEntry->offset);
207 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
208 for (int i=0; i<nameTable->count; ++i, ++nameRecord) {
209 if (nameRecord->nameID == 1
210 && nameRecord->platformID == 3 // Windows
211 && nameRecord->languageID == 0x0409) { // US English
212 const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
213 + nameTable->stringOffset
214 + nameRecord->offset;
216 const BigEndian<quint16> *s = reinterpret_cast<const BigEndian<quint16> *>(ptr);
217 for (int j=0; j<nameRecord->length / sizeof(quint16); ++j)
228 QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
230 TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
231 if (nameTableDirectoryEntry == 0)
234 QString oldFamilyName = familyName(nameTableDirectoryEntry);
236 // Reserve size for name table header, five required name records and string
237 const int requiredRecordCount = 5;
238 quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
240 int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
241 int newFamilyNameSize = newFamilyName.size() * sizeof(quint16);
243 const QString regularString = QString::fromLatin1("Regular");
244 int regularStringSize = regularString.size() * sizeof(quint16);
246 // Align table size of table to 32 bits (pad with 0)
247 int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
249 QByteArray newNameTable(fullSize, char(0));
252 NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
253 nameTable->count = requiredRecordCount;
254 nameTable->stringOffset = sizeOfHeader;
256 NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
257 for (int i=0; i<requiredRecordCount; ++i, nameRecord++) {
258 nameRecord->nameID = nameIds[i];
259 nameRecord->encodingID = 1;
260 nameRecord->languageID = 0x0409;
261 nameRecord->platformID = 3;
262 nameRecord->length = newFamilyNameSize;
264 // Special case for sub-family
265 if (nameIds[i] == 4) {
266 nameRecord->offset = newFamilyNameSize;
267 nameRecord->length = regularStringSize;
271 // nameRecord now points to string data
272 BigEndian<quint16> *stringStorage = reinterpret_cast<BigEndian<quint16> *>(nameRecord);
273 const quint16 *sourceString = newFamilyName.utf16();
274 for (int i=0; i<newFamilyName.size(); ++i)
275 stringStorage[i] = sourceString[i];
276 stringStorage += newFamilyName.size();
278 sourceString = regularString.utf16();
279 for (int i=0; i<regularString.size(); ++i)
280 stringStorage[i] = sourceString[i];
283 quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
284 quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
286 quint32 checkSum = 0;
290 nameTableDirectoryEntry->checkSum = checkSum;
291 nameTableDirectoryEntry->offset = m_fontData.size();
292 nameTableDirectoryEntry->length = fullSize;
294 m_fontData.append(newNameTable);
296 return oldFamilyName;
299 #if !defined(QT_NO_DIRECTWRITE)
301 class DirectWriteFontFileStream: public IDWriteFontFileStream
304 DirectWriteFontFileStream(const QByteArray &fontData)
305 : m_fontData(fontData)
306 , m_referenceCount(0)
310 ~DirectWriteFontFileStream()
314 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
315 ULONG STDMETHODCALLTYPE AddRef();
316 ULONG STDMETHODCALLTYPE Release();
318 HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
319 UINT64 fragmentSize, OUT void **fragmentContext);
320 void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
321 HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
322 HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
325 QByteArray m_fontData;
326 ULONG m_referenceCount;
329 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
331 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
337 return E_NOINTERFACE;
341 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
343 return InterlockedIncrement(&m_referenceCount);
346 ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
348 ULONG newCount = InterlockedDecrement(&m_referenceCount);
354 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
355 const void **fragmentStart,
358 OUT void **fragmentContext)
360 *fragmentContext = NULL;
361 if (fragmentSize + fileOffset <= m_fontData.size()) {
362 *fragmentStart = m_fontData.data() + fileOffset;
365 *fragmentStart = NULL;
370 void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
374 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
376 *fileSize = m_fontData.size();
380 HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
386 class DirectWriteFontFileLoader: public IDWriteFontFileLoader
389 DirectWriteFontFileLoader() : m_referenceCount(0) {}
391 ~DirectWriteFontFileLoader()
395 inline void addKey(const void *key, const QByteArray &fontData)
397 Q_ASSERT(!m_fontDatas.contains(key));
398 m_fontDatas.insert(key, fontData);
401 inline void removeKey(const void *key)
403 m_fontDatas.remove(key);
406 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
407 ULONG STDMETHODCALLTYPE AddRef();
408 ULONG STDMETHODCALLTYPE Release();
410 HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
411 UINT32 fontFileReferenceKeySize,
412 OUT IDWriteFontFileStream **fontFileStream);
415 ULONG m_referenceCount;
416 QHash<const void *, QByteArray> m_fontDatas;
419 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
422 if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
428 return E_NOINTERFACE;
432 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
434 return InterlockedIncrement(&m_referenceCount);
437 ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
439 ULONG newCount = InterlockedDecrement(&m_referenceCount);
445 HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
446 void const *fontFileReferenceKey,
447 UINT32 fontFileReferenceKeySize,
448 IDWriteFontFileStream **fontFileStream)
450 Q_UNUSED(fontFileReferenceKeySize);
452 if (fontFileReferenceKeySize != sizeof(const void *)) {
453 qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size");
457 const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
458 *fontFileStream = NULL;
459 if (!m_fontDatas.contains(key))
462 QByteArray fontData = m_fontDatas.value(key);
463 DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
465 *fontFileStream = stream;
470 class CustomFontFileLoader
473 CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0)
475 HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
476 __uuidof(IDWriteFactory),
477 reinterpret_cast<IUnknown **>(&m_directWriteFactory));
479 qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: "
480 "DWriteCreateFactory failed.");
482 m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
483 m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
487 ~CustomFontFileLoader()
489 if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
490 m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
492 if (m_directWriteFactory != 0)
493 m_directWriteFactory->Release();
496 void addKey(const void *key, const QByteArray &fontData)
498 if (m_directWriteFontFileLoader != 0)
499 m_directWriteFontFileLoader->addKey(key, fontData);
502 void removeKey(const void *key)
504 if (m_directWriteFontFileLoader != 0)
505 m_directWriteFontFileLoader->removeKey(key);
508 IDWriteFontFileLoader *loader() const
510 return m_directWriteFontFileLoader;
514 IDWriteFactory *m_directWriteFactory;
515 DirectWriteFontFileLoader *m_directWriteFontFileLoader;
520 } // Anonymous namespace
523 // From qfontdatabase_win.cpp
524 extern QFontEngine *qt_load_font_engine_win(const QFontDef &request);
525 // From qfontdatabase.cpp
526 extern QFont::Weight weightFromInteger(int weight);
528 void QRawFontPrivate::platformCleanUp()
530 if (fontHandle != NULL) {
531 if (ptrRemoveFontMemResourceEx == NULL) {
532 void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
533 ptrRemoveFontMemResourceEx =
534 reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
537 if (ptrRemoveFontMemResourceEx == NULL) {
538 qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32");
541 ptrRemoveFontMemResourceEx(fontHandle);
547 void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData,
549 QFont::HintingPreference hintingPreference)
551 QByteArray fontData(_fontData);
552 EmbeddedFont font(fontData);
554 #if !defined(QT_NO_DIRECTWRITE)
555 if (hintingPreference == QFont::PreferDefaultHinting
556 || hintingPreference == QFont::PreferFullHinting)
562 QString uniqueFamilyName = QString::fromLatin1("f")
563 + QString::number(guid.Data1, 36) + QLatin1Char('-')
564 + QString::number(guid.Data2, 36) + QLatin1Char('-')
565 + QString::number(guid.Data3, 36) + QLatin1Char('-')
566 + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
568 QString actualFontName = font.changeFamilyName(uniqueFamilyName);
569 if (actualFontName.isEmpty()) {
570 qWarning("QRawFont::platformLoadFromData: Can't change family name of font");
574 if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) {
575 void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
576 ptrRemoveFontMemResourceEx =
577 reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
579 func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx");
580 ptrAddFontMemResourceEx =
581 reinterpret_cast<QRawFontPrivate::PtrAddFontMemResourceEx>(func);
584 Q_ASSERT(fontHandle == NULL);
585 if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) {
587 fontData = font.data();
588 fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count);
590 if (count == 0 && fontHandle != NULL) {
591 ptrRemoveFontMemResourceEx(fontHandle);
596 if (fontHandle == NULL) {
597 qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed");
600 request.family = uniqueFamilyName;
601 request.pixelSize = pixelSize;
602 request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
603 request.hintingPreference = hintingPreference;
605 fontEngine = qt_load_font_engine_win(request);
606 if (request.family != fontEngine->fontDef.family) {
607 qWarning("QRawFont::platformLoadFromData: Failed to load font. "
608 "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family));
609 if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
613 Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0);
615 // Override the generated font name
616 static_cast<QFontEngineWin *>(fontEngine)->uniqueFamilyName = uniqueFamilyName;
617 fontEngine->fontDef.family = actualFontName;
618 fontEngine->ref.ref();
622 #if !defined(QT_NO_DIRECTWRITE)
624 CustomFontFileLoader fontFileLoader;
625 fontFileLoader.addKey(this, fontData);
627 IDWriteFactory *factory = NULL;
628 HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
629 __uuidof(IDWriteFactory),
630 reinterpret_cast<IUnknown **>(&factory));
632 qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed");
636 IDWriteFontFile *fontFile = NULL;
639 hres = factory->CreateCustomFontFileReference(&key, sizeof(void *),
640 fontFileLoader.loader(), &fontFile);
642 qErrnoWarning(hres, "QRawFont::platformLoadFromData: "
643 "CreateCustomFontFileReference failed");
648 BOOL isSupportedFontType;
649 DWRITE_FONT_FILE_TYPE fontFileType;
650 DWRITE_FONT_FACE_TYPE fontFaceType;
651 UINT32 numberOfFaces;
652 fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
653 if (!isSupportedFontType) {
659 IDWriteFontFace *directWriteFontFace = NULL;
660 hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE,
661 &directWriteFontFace);
663 qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed");
671 fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize);
673 // Get font family from font data
674 fontEngine->fontDef.family = font.familyName();
675 fontEngine->ref.ref();
677 directWriteFontFace->Release();
682 // Get style and weight info
683 if (fontEngine != 0) {
684 TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
685 if (os2TableEntry != 0) {
686 const OS2Table *os2Table =
687 reinterpret_cast<const OS2Table *>(fontData.constData()
688 + os2TableEntry->offset);
690 bool italic = os2Table->selection & 1;
691 bool oblique = os2Table->selection & 128;
694 fontEngine->fontDef.style = QFont::StyleItalic;
696 fontEngine->fontDef.style = QFont::StyleOblique;
698 fontEngine->fontDef.style = QFont::StyleNormal;
700 fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass);
707 #endif // QT_NO_RAWFONT