From af5abe41d037d8452323ae738833474ff4bfbda2 Mon Sep 17 00:00:00 2001 From: Dmitri Ovodok Date: Fri, 16 Nov 2018 14:14:42 +0200 Subject: [PATCH] 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. --- libmscore/sym.cpp | 58 ++++++++++++++++++++++++++++------------------- libmscore/sym.h | 7 +++--- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/libmscore/sym.cpp b/libmscore/sym.cpp index a69f8ccfb3..e7af65b19a 100644 --- a/libmscore/sym.cpp +++ b/libmscore/sym.cpp @@ -40,7 +40,7 @@ QVector ScoreFont::_scoreFonts { ScoreFont("MuseJazz", "MuseJazz", ":/fonts/musejazz/", "MuseJazz.otf" ), }; -QJsonObject ScoreFont::_glyphnamesJson; +std::array 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; } //--------------------------------------------------------- diff --git a/libmscore/sym.h b/libmscore/sym.h index c1132c4148..99a985e122 100644 --- a/libmscore/sym.h +++ b/libmscore/sym.h @@ -2778,7 +2778,7 @@ class ScoreFont { mutable QFont* font { 0 }; static QVector _scoreFonts; - static QJsonObject _glyphnamesJson; + static std::array _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& 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();