LCOV - code coverage report
Current view: top level - muse/framework/draw/internal - fontsdatabase.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 59.6 % 114 68
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2024 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : #include "fontsdatabase.h"
      23              : 
      24              : #include "muse_framework_config.h"
      25              : 
      26              : #ifdef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
      27              : #include <QFontDatabase>
      28              : #include <QFont>
      29              : #endif
      30              : 
      31              : #include "global/io/file.h"
      32              : 
      33              : #include "log.h"
      34              : 
      35              : using namespace muse;
      36              : using namespace muse::draw;
      37              : 
      38              : #ifndef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
      39              : static int s_fontID = -1;
      40              : #endif
      41              : 
      42          149 : void FontsDatabase::setDefaultFont(Font::Type type, const FontDataKey& key)
      43              : {
      44          149 :     m_defaults[type] = key;
      45          149 :     m_changed.notify();
      46          149 : }
      47              : 
      48          149 : void FontsDatabase::insertSubstitution(const String& familyName, const String& substituteName)
      49              : {
      50          149 :     FontDataKey familyKey(familyName);
      51          149 :     FontDataKey substituteKey(substituteName);
      52          149 :     m_familySubstitutions[familyKey].push_back(substituteKey);
      53              : 
      54              : #ifdef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
      55          149 :     QFont::insertSubstitution(familyName, substituteName);
      56              : #endif
      57              : 
      58          149 :     m_changed.notify();
      59          149 : }
      60              : 
      61            2 : void FontsDatabase::removeSubstitutions(const String& familyName, const std::vector<String>& substituteNames)
      62              : {
      63            2 :     auto it = m_familySubstitutions.find(FontDataKey(familyName));
      64            2 :     if (it == m_familySubstitutions.end()) {
      65            0 :         return;
      66              :     }
      67              : 
      68            2 :     std::vector<FontDataKey>& substitutes = it->second;
      69            2 :     size_t removed = 0;
      70            4 :     for (const String& substituteName : substituteNames) {
      71            2 :         removed += std::erase(substitutes, FontDataKey(substituteName));
      72              :     }
      73              : 
      74            2 :     if (removed == 0) {
      75            0 :         return;
      76              :     }
      77              : 
      78              : #ifdef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
      79            2 :     QFont::removeSubstitutions(familyName);
      80            4 :     for (const FontDataKey& key : substitutes) {
      81            2 :         QFont::insertSubstitution(familyName, key.family().id().toQString());
      82              :     }
      83              : #endif
      84              : 
      85            2 :     if (substitutes.empty()) {
      86            1 :         m_familySubstitutions.erase(it);
      87              :     }
      88              : 
      89            2 :     m_changed.notify();
      90              : }
      91              : 
      92            0 : const FontDataKey& FontsDatabase::defaultFont(Font::Type type) const
      93              : {
      94            0 :     auto it = m_defaults.find(type);
      95            0 :     if (it != m_defaults.end()) {
      96            0 :         return it->second;
      97              :     }
      98              : 
      99            0 :     it = m_defaults.find(Font::Type::Unknown);
     100            0 :     IF_ASSERT_FAILED(it != m_defaults.end()) {
     101            0 :         static FontDataKey null;
     102            0 :         return null;
     103              :     }
     104            0 :     return it->second;
     105              : }
     106              : 
     107          700 : int FontsDatabase::addFont(const FontDataKey& key, const io::path_t& path)
     108              : {
     109          700 :     return addFont(key, std::make_shared<io::File>(path));
     110              : }
     111              : 
     112          700 : int FontsDatabase::addFont(const FontDataKey& key, std::shared_ptr<io::IODevice> device)
     113              : {
     114          700 :     if (!device) {
     115            0 :         LOGE() << "no device for font: " << key.family().id();
     116            0 :         return -1;
     117              :     }
     118              : 
     119         1400 :     const std::string filePath = device->meta("file_path");
     120          700 :     ByteArray data;
     121          700 :     if (filePath.empty()) {
     122            0 :         if (device->open(io::IODevice::ReadOnly)) {
     123            0 :             data = device->readAll();
     124              :         }
     125            0 :         if (data.empty()) {
     126            0 :             LOGE() << "failed read font: " << key.family().id();
     127            0 :             return -1;
     128              :         }
     129          700 :     } else if (!io::File::exists(filePath)) {
     130            0 :         LOGW() << "font file not found: " << filePath;
     131            0 :         return -1;
     132              :     }
     133              : 
     134              : #ifdef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
     135          700 :     const int id = filePath.empty()
     136          700 :                    ? QFontDatabase::addApplicationFontFromData(data.toQByteArray())
     137          700 :                    : QFontDatabase::addApplicationFont(QString::fromStdString(filePath));
     138          700 :     if (id < 0) {
     139            0 :         LOGW() << "failed register font: " << key.family().id();
     140            0 :         return id;
     141              :     }
     142              : #else
     143              :     const int id = ++s_fontID;
     144              : #endif
     145              : 
     146          700 :     auto it = m_fonts.find(key);
     147          700 :     if (it != m_fonts.end()) {
     148            0 :         release(it->second);
     149            0 :         m_fonts.erase(it);
     150              :     }
     151              : 
     152          700 :     m_fonts.insert({ key, FontInfo { id, key, std::move(device) } });
     153          700 :     m_changed.notify();
     154              : 
     155          700 :     return id;
     156          700 : }
     157              : 
     158            0 : void FontsDatabase::removeFont(const FontDataKey& key)
     159              : {
     160            0 :     auto it = m_fonts.find(key);
     161            0 :     if (it == m_fonts.end()) {
     162            0 :         return;
     163              :     }
     164              : 
     165            0 :     release(it->second);
     166            0 :     m_fonts.erase(it);
     167            0 :     m_changed.notify();
     168              : }
     169              : 
     170            0 : void FontsDatabase::release(const FontInfo& fi)
     171              : {
     172              : #ifdef MUSE_MODULE_DRAW_USE_QTFONTMETRICS
     173            0 :     if (fi.valid()) {
     174            0 :         QFontDatabase::removeApplicationFont(fi.id);
     175              :     }
     176              : #else
     177              :     UNUSED(fi);
     178              : #endif
     179            0 : }
     180              : 
     181          312 : FontDataKey FontsDatabase::actualFont(const FontDataKey& requireKey, Font::Type type) const
     182              : {
     183          312 :     if (fontInfo(requireKey).valid()) {
     184          312 :         return requireKey;
     185              :     }
     186              : 
     187            0 :     FontDataKey def = defaultFont(type);
     188            0 :     LOGW() << "not found required font: " << requireKey.family().id() << ", will be using default: " << def.family().id();
     189            0 :     return def;
     190            0 : }
     191              : 
     192          106 : std::vector<FontDataKey> FontsDatabase::substitutionFonts(const FontDataKey& requireKey) const
     193              : {
     194          106 :     auto familyIt = m_familySubstitutions.find(FontDataKey(requireKey.family()));
     195          106 :     if (familyIt != m_familySubstitutions.end()) {
     196            3 :         return familyIt->second;
     197              :     }
     198              : 
     199          103 :     static std::vector<FontDataKey> null;
     200          103 :     return null;
     201              : }
     202              : 
     203          208 : FontData FontsDatabase::fontData(const FontDataKey& requireKey, Font::Type type) const
     204              : {
     205          208 :     FontDataKey key = actualFont(requireKey, type);
     206          208 :     const FontInfo& info = fontInfo(key);
     207          208 :     if (!info.valid()) {
     208            0 :         return FontData();
     209              :     }
     210              : 
     211          208 :     if (!info.device->isOpen() && !info.device->open(io::IODevice::ReadOnly)) {
     212            0 :         LOGE() << "failed open font: " << key.family().id();
     213            0 :         return FontData();
     214              :     }
     215              : 
     216          208 :     info.device->seek(0);
     217          208 :     ByteArray data = info.device->readAll();
     218          208 :     if (data.empty()) {
     219            0 :         LOGE() << "failed read font: " << key.family().id();
     220            0 :         return FontData();
     221              :     }
     222              : 
     223          208 :     return FontData { key, data };
     224          208 : }
     225              : 
     226           23 : async::Notification FontsDatabase::changed() const
     227              : {
     228           23 :     return m_changed;
     229              : }
     230              : 
     231          520 : const FontsDatabase::FontInfo& FontsDatabase::fontInfo(const FontDataKey& key) const
     232              : {
     233          520 :     auto it = m_fonts.find(key);
     234          520 :     if (it != m_fonts.end()) {
     235          520 :         return it->second;
     236              :     }
     237              : 
     238            0 :     static FontInfo null;
     239            0 :     return null;
     240              : }
        

Generated by: LCOV version 2.0-1