From 2f521438ebe5306d97b24a530ed4dc025b12052b Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Fri, 7 Feb 2020 07:53:17 +0100 Subject: [PATCH] DirectWrite font db: Fix writing system detection The implementation here was accidentally missing from the first commit. We use the OS/2 table for determining the writing system support as intended by the font designer, and fall back to actually checking the Unicode ranges if the table should be missing. Change-Id: Ibfdf76c27f3a94eda2142b3e269a1ca30d4bc045 Reviewed-by: Lars Knoll --- src/gui/text/qfontdatabase.cpp | 17 ++++--- src/gui/text/qplatformfontdatabase.cpp | 26 ++++++++++ src/gui/text/qplatformfontdatabase.h | 1 + .../mac/qcoretextfontdatabase.mm | 12 +---- .../qwindowsdirectwritefontdatabase.cpp | 51 +++++++++++++++---- 5 files changed, 78 insertions(+), 29 deletions(-) diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 29f56f5c85..a43af37097 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -617,6 +617,12 @@ static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSyst return false; } +Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script) +{ + return QFontDatabase::WritingSystem(std::find(scriptForWritingSystem, + scriptForWritingSystem + QFontDatabase::WritingSystemsCount, + script) - scriptForWritingSystem); +} /*! \internal @@ -833,9 +839,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo QStringList preferredFallbacks; QStringList otherFallbacks; - size_t writingSystem = std::find(scriptForWritingSystem, - scriptForWritingSystem + QFontDatabase::WritingSystemsCount, - script) - scriptForWritingSystem; + auto writingSystem = qt_writing_system_for_script(script); if (writingSystem >= QFontDatabase::WritingSystemsCount) writingSystem = QFontDatabase::Any; @@ -1272,8 +1276,7 @@ static int match(int script, const QFontDef &request, load(family_name, script); - size_t writingSystem = std::find(scriptForWritingSystem, scriptForWritingSystem + - QFontDatabase::WritingSystemsCount, script) - scriptForWritingSystem; + auto writingSystem = qt_writing_system_for_script(script); if (writingSystem >= QFontDatabase::WritingSystemsCount) writingSystem = QFontDatabase::Any; @@ -2876,9 +2879,7 @@ QString QFontDatabase::resolveFontFamilyAlias(const QString &family) Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script, const QStringList &families) { - size_t writingSystem = std::find(scriptForWritingSystem, - scriptForWritingSystem + QFontDatabase::WritingSystemsCount, - script) - scriptForWritingSystem; + size_t writingSystem = qt_writing_system_for_script(script); if (writingSystem == QFontDatabase::Any || writingSystem >= QFontDatabase::WritingSystemsCount) { return families; diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp index 48ba8987f3..4ff2ad3a41 100644 --- a/src/gui/text/qplatformfontdatabase.cpp +++ b/src/gui/text/qplatformfontdatabase.cpp @@ -533,6 +533,32 @@ enum CsbBits { SymbolCsbBit = 31 }; +/*! + Helper function that determines the writing system support based on the contents of the OS/2 table + in the font. + + \since 6.0 +*/ +QSupportedWritingSystems QPlatformFontDatabase::writingSystemsFromOS2Table(const char *os2Table, size_t length) +{ + if (length >= 86) { + quint32 unicodeRange[4] = { + qFromBigEndian(os2Table + 42), + qFromBigEndian(os2Table + 46), + qFromBigEndian(os2Table + 50), + qFromBigEndian(os2Table + 54) + }; + quint32 codePageRange[2] = { + qFromBigEndian(os2Table + 78), + qFromBigEndian(os2Table + 82) + }; + + return writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + } + + return QSupportedWritingSystems(); +} + /*! Helper function that determines the writing systems support by a given \a unicodeRange and \a codePageRange. diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h index f79c5db625..d05bcb372b 100644 --- a/src/gui/text/qplatformfontdatabase.h +++ b/src/gui/text/qplatformfontdatabase.h @@ -127,6 +127,7 @@ public: // helper static QSupportedWritingSystems writingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]); + static QSupportedWritingSystems writingSystemsFromOS2Table(const char *os2Table, size_t length); static QFont::Weight weightFromInteger(int weight); //callback diff --git a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm index 894919a1c8..bc55efd23d 100644 --- a/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm +++ b/src/platformsupport/fontdatabases/mac/qcoretextfontdatabase.mm @@ -268,17 +268,7 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd) Q_UNREACHABLE(); Q_ASSERT(length >= 86); } - quint32 unicodeRange[4] = { - qFromBigEndian(os2Table.data() + 42), - qFromBigEndian(os2Table.data() + 46), - qFromBigEndian(os2Table.data() + 50), - qFromBigEndian(os2Table.data() + 54) - }; - quint32 codePageRange[2] = { - qFromBigEndian(os2Table.data() + 78), - qFromBigEndian(os2Table.data() + 82) - }; - fd->writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + fd->writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast(os2Table.data()), length); } } diff --git a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp index 5a1ff935b8..a0483c2413 100644 --- a/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp +++ b/src/platformsupport/fontdatabases/windows/qwindowsdirectwritefontdatabase.cpp @@ -40,6 +40,7 @@ #include "qwindowsdirectwritefontdatabase_p.h" #include "qwindowsfontenginedirectwrite_p.h" +#include #include #include @@ -174,16 +175,6 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty()) englishLocaleFamilyName = familyName; - QVarLengthArray ranges(QFontDatabase::WritingSystemsCount); - - uint count = 0; - if (SUCCEEDED(font1->GetUnicodeRanges(QFontDatabase::WritingSystemsCount, ranges.data(), &count))) { - // ### - } - QSupportedWritingSystems writingSystems; - writingSystems.setSupported(QFontDatabase::Any); - writingSystems.setSupported(QFontDatabase::Latin); - { IDWriteLocalizedStrings *names; if (SUCCEEDED(font1->GetFaceNames(&names))) { @@ -199,7 +190,47 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName) IDWriteFontFace *face = nullptr; if (SUCCEEDED(font->CreateFontFace(&face))) { + QSupportedWritingSystems writingSystems; + + const void *tableData = nullptr; + UINT32 tableSize; + void *tableContext = nullptr; + BOOL exists; + HRESULT hr = face->TryGetFontTable(qbswap(MAKE_TAG('O','S','/','2')), + &tableData, + &tableSize, + &tableContext, + &exists); + if (SUCCEEDED(hr) && exists) { + writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast(tableData), tableSize); + } else { // Fall back to checking first character of each Unicode range in font (may include too many writing systems) + quint32 rangeCount; + hr = font1->GetUnicodeRanges(0, nullptr, &rangeCount); + + if (rangeCount > 0) { + QVarLengthArray ranges(rangeCount); + + hr = font1->GetUnicodeRanges(rangeCount, ranges.data(), &rangeCount); + if (SUCCEEDED(hr)) { + for (uint i = 0; i < rangeCount; ++i) { + QChar::Script script = QChar::script(ranges.at(i).first); + + Q_GUI_EXPORT QFontDatabase::WritingSystem qt_writing_system_for_script(int script); + QFontDatabase::WritingSystem writingSystem = qt_writing_system_for_script(script); + + if (writingSystem > QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount) + writingSystems.setSupported(writingSystem); + } + } else { + const QString errorString = qt_error_string(int(hr)); + qCWarning(lcQpaFonts) << "Failed to get unicode ranges for font" << englishLocaleFamilyName << englishLocaleStyleName << ":" << errorString; + } + } + } + if (!englishLocaleStyleName.isEmpty() || defaultLocaleStyleName.isEmpty()) { + qCDebug(lcQpaFonts) << "Font" << englishLocaleFamilyName << englishLocaleStyleName << "supports writing systems:" << writingSystems; + QPlatformFontDatabase::registerFont(englishLocaleFamilyName, englishLocaleStyleName, QString(), weight, style, stretch, antialias, scalable, size, fixed, writingSystems, face); face->AddRef(); }