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 <lars.knoll@qt.io>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2020-02-07 07:53:17 +01:00
parent 63a559845c
commit 2f521438eb
5 changed files with 78 additions and 29 deletions

View File

@ -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;

View File

@ -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<quint32>(os2Table + 42),
qFromBigEndian<quint32>(os2Table + 46),
qFromBigEndian<quint32>(os2Table + 50),
qFromBigEndian<quint32>(os2Table + 54)
};
quint32 codePageRange[2] = {
qFromBigEndian<quint32>(os2Table + 78),
qFromBigEndian<quint32>(os2Table + 82)
};
return writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
}
return QSupportedWritingSystems();
}
/*!
Helper function that determines the writing systems support by a given
\a unicodeRange and \a codePageRange.

View File

@ -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

View File

@ -268,17 +268,7 @@ static void getFontDescription(CTFontDescriptorRef font, FontDescription *fd)
Q_UNREACHABLE();
Q_ASSERT(length >= 86);
}
quint32 unicodeRange[4] = {
qFromBigEndian<quint32>(os2Table.data() + 42),
qFromBigEndian<quint32>(os2Table.data() + 46),
qFromBigEndian<quint32>(os2Table.data() + 50),
qFromBigEndian<quint32>(os2Table.data() + 54)
};
quint32 codePageRange[2] = {
qFromBigEndian<quint32>(os2Table.data() + 78),
qFromBigEndian<quint32>(os2Table.data() + 82)
};
fd->writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
fd->writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(os2Table.data()), length);
}
}

View File

@ -40,6 +40,7 @@
#include "qwindowsdirectwritefontdatabase_p.h"
#include "qwindowsfontenginedirectwrite_p.h"
#include <QtCore/qendian.h>
#include <QtCore/qstringbuilder.h>
#include <QtCore/qvarlengtharray.h>
@ -174,16 +175,6 @@ void QWindowsDirectWriteFontDatabase::populateFamily(const QString &familyName)
if (defaultLocaleFamilyName.isEmpty() && englishLocaleFamilyName.isEmpty())
englishLocaleFamilyName = familyName;
QVarLengthArray<DWRITE_UNICODE_RANGE, 64> 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<quint32>(MAKE_TAG('O','S','/','2')),
&tableData,
&tableSize,
&tableContext,
&exists);
if (SUCCEEDED(hr) && exists) {
writingSystems = QPlatformFontDatabase::writingSystemsFromOS2Table(reinterpret_cast<const char *>(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<DWRITE_UNICODE_RANGE, QChar::ScriptCount> 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();
}