fix #276354: lookup character codes in SMuFL code table if no font-specific symbol is found

This commit does three things:
1) Constructs a code table for SMuFL symbols that is common to all
used fonts. The table is constructed from fonts/smufl/glyphnames.json
2) Replaces repeated calls to the object representing that json file
by a lookup in the code table obtained from that file. This is simpler
to reuse and avoids unnecessary repeated string parsing operations.
3) The fix itself: ScoreFont::toString now looks for a symbol
in the common SMuFL table if nothing is found in the font itself.
That way a correct code for the queried symbol can be returned even
if the font itself is not able to render it.
Previously -1 was returned which led to adding symbols which cannot
be correctly displayed by any font at all.
This commit is contained in:
Dmitri Ovodok 2018-11-16 14:14:42 +02:00
parent 09f90b22f5
commit af5abe41d0
2 changed files with 39 additions and 26 deletions

View file

@ -40,7 +40,7 @@ QVector<ScoreFont> ScoreFont::_scoreFonts {
ScoreFont("MuseJazz", "MuseJazz", ":/fonts/musejazz/", "MuseJazz.otf" ),
};
QJsonObject ScoreFont::_glyphnamesJson;
std::array<uint, size_t(SymId::lastSym)+1> ScoreFont::_mainSymCodeTable { 0 };
//---------------------------------------------------------
// table of symbol names
@ -5781,13 +5781,22 @@ const char* Sym::id2name(SymId id)
void initScoreFonts()
{
ScoreFont::initGlyphNamesJson();
QJsonObject glyphNamesJson(ScoreFont::initGlyphNamesJson());
if (glyphNamesJson.empty())
qFatal("initGlyphNamesJson failed");
int error = FT_Init_FreeType(&ftlib);
if (!ftlib || error)
qFatal("init freetype library failed");
int index = 0;
for (auto i : Sym::symNames)
Sym::lnhash.insert(i, SymId(index++));
for (size_t i = 0; i < Sym::symNames.size(); ++i) {
const char* name = Sym::symNames[i];
Sym::lnhash.insert(name, SymId(i));
bool ok;
uint code = glyphNamesJson.value(name).toObject().value("codepoint").toString().mid(2).toUInt(&ok, 16);
if (ok)
ScoreFont::_mainSymCodeTable[i] = code;
else
qDebug("codepoint not recognized for glyph %s", qPrintable(name));
}
for (oldName i : oldNames)
Sym::lonhash.insert(i.name, SymId(i.symId));
QFont::insertSubstitution("MScore Text", "Bravura Text");
@ -5812,7 +5821,15 @@ static QString codeToString(uint code)
QString ScoreFont::toString(SymId id) const
{
return codeToString(sym(id).code());
const Sym& s = sym(id);
int code;
if (s.isValid())
code = s.code();
else {
// fallback: search in the common SMuFL table
code = _mainSymCodeTable[size_t(id)];
}
return codeToString(code);
}
//---------------------------------------------------------
@ -5865,18 +5882,13 @@ void ScoreFont::load()
qreal pixelSize = 200.0;
FT_Set_Pixel_Sizes(face, 0, int(pixelSize+.5));
for (auto i : ScoreFont::glyphNamesJson().keys()) {
bool ok;
int code = ScoreFont::glyphNamesJson().value(i).toObject().value("codepoint").toString().mid(2).toInt(&ok, 16);
if (!ok)
qDebug("codepoint not recognized for glyph %s", qPrintable(i));
if (Sym::lnhash.contains(i)) {
SymId symId = Sym::lnhash.value(i);
Sym* sym = &_symbols[int(symId)];
computeMetrics(sym, code);
}
else
qDebug("unknown glyph: %s", qPrintable(i));
for (size_t id = 0; id < _mainSymCodeTable.size(); ++id) {
uint code = _mainSymCodeTable[id];
if (code == 0)
continue;
SymId symId = SymId(id);
Sym* sym = &_symbols[int(symId)];
computeMetrics(sym, code);
}
QJsonParseError error;
@ -6209,22 +6221,22 @@ const char* ScoreFont::fallbackTextFont()
// initGlyphNamesJson
//---------------------------------------------------------
bool ScoreFont::initGlyphNamesJson()
QJsonObject ScoreFont::initGlyphNamesJson()
{
QFile fi(":fonts/smufl/glyphnames.json");
if (!fi.open(QIODevice::ReadOnly)) {
qDebug("ScoreFont: open glyph names file <%s> failed", qPrintable(fi.fileName()));
return false;
return QJsonObject();
}
QJsonParseError error;
_glyphnamesJson = QJsonDocument::fromJson(fi.readAll(), &error).object();
QJsonObject glyphNamesJson = QJsonDocument::fromJson(fi.readAll(), &error).object();
if (error.error != QJsonParseError::NoError) {
qDebug("Json parse error in <%s>(offset: %d): %s", qPrintable(fi.fileName()),
error.offset, qPrintable(error.errorString()));
return false;
return QJsonObject();
}
fi.close();
return true;
return glyphNamesJson;
}
//---------------------------------------------------------

View file

@ -2778,7 +2778,7 @@ class ScoreFont {
mutable QFont* font { 0 };
static QVector<ScoreFont> _scoreFonts;
static QJsonObject _glyphnamesJson;
static std::array<uint, size_t(SymId::lastSym)+1> _mainSymCodeTable;
void load();
void computeMetrics(Sym* sym, int code);
@ -2802,8 +2802,7 @@ class ScoreFont {
static ScoreFont* fallbackFont();
static const char* fallbackTextFont();
static const QVector<ScoreFont>& scoreFonts() { return _scoreFonts; }
static bool initGlyphNamesJson();
static const QJsonObject& glyphNamesJson() { return _glyphnamesJson; }
static QJsonObject initGlyphNamesJson();
QString toString(SymId) const;
QPixmap sym2pixmap(SymId, qreal) { return QPixmap(); } // TODOxxxx
@ -2838,6 +2837,8 @@ class ScoreFont {
bool useFallbackFont(SymId id) const;
const Sym& sym(SymId id) const { return _symbols[int(id)]; }
friend void initScoreFonts();
};
extern void initScoreFonts();