WinRT: Use registerFontFamily to reduce font registration overhead
Adopt to the new lazy font loading strategy in order to reduce memory and startup time associated with populating the entire font database. Change-Id: I0134cc123f73cb8485fe85c4a6b8e3b3a3a2cab0 Reviewed-by: Oliver Wolff <oliver.wolff@digia.com>
This commit is contained in:
parent
071098b08b
commit
244e2ef7b9
@ -63,7 +63,7 @@ QString QWinRTFontDatabase::fontDir() const
|
||||
fontDirectory = applicationDirPath + QLatin1String("/fonts");
|
||||
if (!QFile::exists(fontDirectory)) {
|
||||
#ifndef Q_OS_WINPHONE
|
||||
if (m_fonts.isEmpty())
|
||||
if (m_fontFamilies.isEmpty())
|
||||
#endif
|
||||
qWarning("No fonts directory found in application package.");
|
||||
fontDirectory = applicationDirPath;
|
||||
@ -78,6 +78,9 @@ QWinRTFontDatabase::~QWinRTFontDatabase()
|
||||
{
|
||||
foreach (IDWriteFontFile *fontFile, m_fonts.keys())
|
||||
fontFile->Release();
|
||||
|
||||
foreach (IDWriteFontFamily *fontFamily, m_fontFamilies)
|
||||
fontFamily->Release();
|
||||
}
|
||||
|
||||
QFont QWinRTFontDatabase::defaultFont() const
|
||||
@ -132,175 +135,196 @@ void QWinRTFontDatabase::populateFontDatabase()
|
||||
}
|
||||
QString familyName = QString::fromWCharArray(familyBuffer.data(), familyNameLength);
|
||||
|
||||
int fontCount = fontFamily->GetFontCount();
|
||||
for (int j = 0; j < fontCount; ++j) {
|
||||
ComPtr<IDWriteFont> font;
|
||||
hr = fontFamily->GetFont(j, &font);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get base font: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
m_fontFamilies.insert(familyName, fontFamily.Detach());
|
||||
|
||||
ComPtr<IDWriteFontFace> baseFontFace;
|
||||
hr = font->CreateFontFace(&baseFontFace);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
ComPtr<IDWriteFontFace1> fontFace;
|
||||
hr = baseFontFace.As(&fontFace);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only try to load true-type fonts
|
||||
DWRITE_FONT_FACE_TYPE type = fontFace->GetType();
|
||||
if (!(type == DWRITE_FONT_FACE_TYPE_TRUETYPE
|
||||
|| type == DWRITE_FONT_FACE_TYPE_TRUETYPE_COLLECTION)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// We can't deal with multi-file fonts
|
||||
quint32 fileCount;
|
||||
hr = fontFace->GetFiles(&fileCount, NULL);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
if (fileCount != 1) // Should not happen as we only look at TT fonts
|
||||
continue;
|
||||
|
||||
ComPtr<IDWriteLocalizedStrings> informationalStrings;
|
||||
BOOL exists;
|
||||
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER,
|
||||
&informationalStrings, &exists);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
QString foundryName;
|
||||
if (exists) {
|
||||
quint32 length;
|
||||
hr = informationalStrings->GetStringLength(0, &length);
|
||||
if (FAILED(hr))
|
||||
qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr)));
|
||||
if (SUCCEEDED(hr)) {
|
||||
QVector<wchar_t> buffer(length + 1);
|
||||
hr = informationalStrings->GetString(0, buffer.data(), buffer.size());
|
||||
if (FAILED(hr))
|
||||
qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr)));
|
||||
if (SUCCEEDED(hr))
|
||||
foundryName = QString::fromWCharArray(buffer.data(), length);
|
||||
}
|
||||
}
|
||||
|
||||
QFont::Weight weight;
|
||||
switch (font->GetWeight()) {
|
||||
case DWRITE_FONT_WEIGHT_THIN:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
|
||||
case DWRITE_FONT_WEIGHT_LIGHT:
|
||||
case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
|
||||
weight = QFont::Light;
|
||||
break;
|
||||
default:
|
||||
case DWRITE_FONT_WEIGHT_NORMAL:
|
||||
case DWRITE_FONT_WEIGHT_MEDIUM:
|
||||
weight = QFont::Normal;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_DEMI_BOLD:
|
||||
weight = QFont::DemiBold;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_BOLD:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
|
||||
weight = QFont::Bold;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_BLACK:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_BLACK:
|
||||
weight = QFont::Black;
|
||||
break;
|
||||
}
|
||||
|
||||
QFont::Style style;
|
||||
switch (font->GetStyle()) {
|
||||
default:
|
||||
case DWRITE_FONT_STYLE_NORMAL:
|
||||
style = QFont::StyleNormal;
|
||||
break;
|
||||
case DWRITE_FONT_STYLE_OBLIQUE:
|
||||
style = QFont::StyleOblique;
|
||||
break;
|
||||
case DWRITE_FONT_STYLE_ITALIC:
|
||||
style = QFont::StyleItalic;
|
||||
break;
|
||||
}
|
||||
|
||||
QFont::Stretch stretch;
|
||||
switch (font->GetStretch()) {
|
||||
default:
|
||||
case DWRITE_FONT_STRETCH_UNDEFINED:
|
||||
case DWRITE_FONT_STRETCH_NORMAL:
|
||||
stretch = QFont::Unstretched;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_ULTRA_CONDENSED:
|
||||
stretch = QFont::UltraCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_CONDENSED:
|
||||
stretch = QFont::ExtraCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_CONDENSED:
|
||||
stretch = QFont::Condensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_SEMI_CONDENSED:
|
||||
stretch = QFont::SemiCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_SEMI_EXPANDED:
|
||||
stretch = QFont::SemiExpanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXPANDED:
|
||||
stretch = QFont::Expanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:
|
||||
stretch = QFont::ExtraExpanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:
|
||||
stretch = QFont::UltraExpanded;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool fixedPitch = fontFace->IsMonospacedFont();
|
||||
|
||||
quint32 unicodeRange[4];
|
||||
quint32 actualRangeCount;
|
||||
hr = fontFace->GetUnicodeRanges(
|
||||
2, reinterpret_cast<DWRITE_UNICODE_RANGE *>(unicodeRange), &actualRangeCount);
|
||||
if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices
|
||||
qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
quint32 codePageRange[2] = { 0, 0 };
|
||||
QSupportedWritingSystems writingSystems =
|
||||
QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
|
||||
|
||||
IDWriteFontFile *fontFile;
|
||||
hr = fontFace->GetFiles(&fileCount, &fontFile);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() };
|
||||
m_fonts.insert(fontFile, description);
|
||||
registerFont(familyName, QString(), foundryName, weight, style, stretch,
|
||||
true, true, 0, fixedPitch, writingSystems, fontFile);
|
||||
}
|
||||
registerFontFamily(familyName);
|
||||
}
|
||||
|
||||
QBasicFontDatabase::populateFontDatabase();
|
||||
}
|
||||
|
||||
void QWinRTFontDatabase::populateFamily(const QString &familyName)
|
||||
{
|
||||
IDWriteFontFamily *fontFamily = m_fontFamilies.value(familyName);
|
||||
if (!fontFamily) {
|
||||
qWarning("The font family %s was not found.", qPrintable(familyName));
|
||||
return;
|
||||
}
|
||||
|
||||
bool fontRegistered = false;
|
||||
const int fontCount = fontFamily->GetFontCount();
|
||||
for (int j = 0; j < fontCount; ++j) {
|
||||
ComPtr<IDWriteFont> font;
|
||||
HRESULT hr = fontFamily->GetFont(j, &font);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip simulated faces
|
||||
if (font->GetSimulations() != DWRITE_FONT_SIMULATIONS_NONE)
|
||||
continue;
|
||||
|
||||
ComPtr<IDWriteFontFace> baseFontFace;
|
||||
hr = font->CreateFontFace(&baseFontFace);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to create base font face: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
ComPtr<IDWriteFontFace1> fontFace;
|
||||
hr = baseFontFace.As(&fontFace);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to create font face: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
// We can't deal with multi-file fonts
|
||||
quint32 fileCount;
|
||||
hr = fontFace->GetFiles(&fileCount, NULL);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font file count: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
if (fileCount != 1)
|
||||
continue;
|
||||
|
||||
ComPtr<IDWriteLocalizedStrings> informationalStrings;
|
||||
BOOL exists;
|
||||
hr = font->GetInformationalStrings(DWRITE_INFORMATIONAL_STRING_MANUFACTURER,
|
||||
&informationalStrings, &exists);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font foundry: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
QString foundryName;
|
||||
if (exists) {
|
||||
quint32 length;
|
||||
hr = informationalStrings->GetStringLength(0, &length);
|
||||
if (FAILED(hr))
|
||||
qWarning("Unable to get foundry name length: %s", qPrintable(qt_error_string(hr)));
|
||||
if (SUCCEEDED(hr)) {
|
||||
QVector<wchar_t> buffer(length + 1);
|
||||
hr = informationalStrings->GetString(0, buffer.data(), buffer.size());
|
||||
if (FAILED(hr))
|
||||
qWarning("Unable to get foundry name: %s", qPrintable(qt_error_string(hr)));
|
||||
if (SUCCEEDED(hr))
|
||||
foundryName = QString::fromWCharArray(buffer.data(), length);
|
||||
}
|
||||
}
|
||||
|
||||
QFont::Weight weight;
|
||||
switch (font->GetWeight()) {
|
||||
case DWRITE_FONT_WEIGHT_THIN:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_LIGHT:
|
||||
case DWRITE_FONT_WEIGHT_LIGHT:
|
||||
case DWRITE_FONT_WEIGHT_SEMI_LIGHT:
|
||||
weight = QFont::Light;
|
||||
break;
|
||||
default:
|
||||
case DWRITE_FONT_WEIGHT_NORMAL:
|
||||
case DWRITE_FONT_WEIGHT_MEDIUM:
|
||||
weight = QFont::Normal;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_DEMI_BOLD:
|
||||
weight = QFont::DemiBold;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_BOLD:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_BOLD:
|
||||
weight = QFont::Bold;
|
||||
break;
|
||||
case DWRITE_FONT_WEIGHT_BLACK:
|
||||
case DWRITE_FONT_WEIGHT_EXTRA_BLACK:
|
||||
weight = QFont::Black;
|
||||
break;
|
||||
}
|
||||
|
||||
QFont::Style style;
|
||||
switch (font->GetStyle()) {
|
||||
default:
|
||||
case DWRITE_FONT_STYLE_NORMAL:
|
||||
style = QFont::StyleNormal;
|
||||
break;
|
||||
case DWRITE_FONT_STYLE_OBLIQUE:
|
||||
style = QFont::StyleOblique;
|
||||
break;
|
||||
case DWRITE_FONT_STYLE_ITALIC:
|
||||
style = QFont::StyleItalic;
|
||||
break;
|
||||
}
|
||||
|
||||
QFont::Stretch stretch;
|
||||
switch (font->GetStretch()) {
|
||||
default:
|
||||
case DWRITE_FONT_STRETCH_UNDEFINED:
|
||||
case DWRITE_FONT_STRETCH_NORMAL:
|
||||
stretch = QFont::Unstretched;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_ULTRA_CONDENSED:
|
||||
stretch = QFont::UltraCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_CONDENSED:
|
||||
stretch = QFont::ExtraCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_CONDENSED:
|
||||
stretch = QFont::Condensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_SEMI_CONDENSED:
|
||||
stretch = QFont::SemiCondensed;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_SEMI_EXPANDED:
|
||||
stretch = QFont::SemiExpanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXPANDED:
|
||||
stretch = QFont::Expanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:
|
||||
stretch = QFont::ExtraExpanded;
|
||||
break;
|
||||
case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:
|
||||
stretch = QFont::UltraExpanded;
|
||||
break;
|
||||
}
|
||||
|
||||
const bool fixedPitch = fontFace->IsMonospacedFont();
|
||||
|
||||
quint32 unicodeRange[4];
|
||||
quint32 actualRangeCount;
|
||||
hr = fontFace->GetUnicodeRanges(
|
||||
2, reinterpret_cast<DWRITE_UNICODE_RANGE *>(unicodeRange), &actualRangeCount);
|
||||
if (FAILED(hr) && hr != E_NOT_SUFFICIENT_BUFFER) { // Ignore insufficient buffer; we only need 4 indices
|
||||
qWarning("Unable to get font unicode range: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
quint32 codePageRange[2] = { 0, 0 };
|
||||
QSupportedWritingSystems writingSystems =
|
||||
QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
|
||||
|
||||
IDWriteFontFile *fontFile;
|
||||
hr = fontFace->GetFiles(&fileCount, &fontFile);
|
||||
if (FAILED(hr)) {
|
||||
qWarning("Unable to get font file: %s", qPrintable(qt_error_string(hr)));
|
||||
continue;
|
||||
}
|
||||
|
||||
FontDescription description = { fontFace->GetIndex(), QUuid::createUuid().toByteArray() };
|
||||
m_fonts.insert(fontFile, description);
|
||||
registerFont(familyName, QString(), foundryName, weight, style, stretch,
|
||||
true, true, 0, fixedPitch, writingSystems, fontFile);
|
||||
fontRegistered = true;
|
||||
}
|
||||
|
||||
// Always populate something to avoid an assert
|
||||
if (!fontRegistered) {
|
||||
registerFont(familyName, QString(), QString(), QFont::Normal, QFont::StyleNormal,
|
||||
QFont::Unstretched, false, false, 0, false, QSupportedWritingSystems(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
|
||||
{
|
||||
if (!handle) // Happens if a font family population failed
|
||||
return 0;
|
||||
|
||||
IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle);
|
||||
if (!m_fonts.contains(fontFile))
|
||||
return QBasicFontDatabase::fontEngine(fontDef, handle);
|
||||
@ -361,6 +385,9 @@ QFontEngine *QWinRTFontDatabase::fontEngine(const QFontDef &fontDef, void *handl
|
||||
|
||||
void QWinRTFontDatabase::releaseHandle(void *handle)
|
||||
{
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
IDWriteFontFile *fontFile = reinterpret_cast<IDWriteFontFile *>(handle);
|
||||
if (m_fonts.contains(fontFile)) {
|
||||
m_fonts.remove(fontFile);
|
||||
|
@ -48,6 +48,7 @@ QT_BEGIN_NAMESPACE
|
||||
|
||||
#ifndef Q_OS_WINPHONE
|
||||
struct IDWriteFontFile;
|
||||
struct IDWriteFontFamily;
|
||||
|
||||
struct FontDescription
|
||||
{
|
||||
@ -64,10 +65,12 @@ public:
|
||||
~QWinRTFontDatabase();
|
||||
QFont defaultFont() const Q_DECL_OVERRIDE;
|
||||
void populateFontDatabase() Q_DECL_OVERRIDE;
|
||||
void populateFamily(const QString &familyName) Q_DECL_OVERRIDE;
|
||||
QFontEngine *fontEngine(const QFontDef &fontDef, void *handle) Q_DECL_OVERRIDE;
|
||||
void releaseHandle(void *handle) Q_DECL_OVERRIDE;
|
||||
private:
|
||||
QHash<IDWriteFontFile *, FontDescription> m_fonts;
|
||||
QHash<QString, IDWriteFontFamily *> m_fontFamilies;
|
||||
#endif // !Q_OS_WINPHONE
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user