LCOV - code coverage report
Current view: top level - muse/framework/draw/internal - fontsengine.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 80.6 % 340 274
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 "fontsengine.h"
      23              : 
      24              : #include "ifontface.h"
      25              : #ifdef MUSE_MODULE_DRAW_USE_FONTFACE_FT
      26              : #include "fontfaceft.h"
      27              : #endif
      28              : #ifdef MUSE_MODULE_DRAW_USE_FONTFACE_XT
      29              : #include "fontfacext.h"
      30              : #endif
      31              : #include "fontfacedu.h"
      32              : 
      33              : #include "log.h"
      34              : 
      35              : using namespace muse;
      36              : using namespace muse::draw;
      37              : 
      38          208 : static bool isFtx(const ByteArray& data)
      39              : {
      40              : #ifdef MUSE_MODULE_DRAW_USE_FONTFACE_XT
      41          208 :     return FontFaceXT::isFtx(data);
      42              : #else
      43              :     UNUSED(data);
      44              :     return false;
      45              : #endif
      46              : }
      47              : 
      48              : static const double DEFAULT_PIXEL_SIZE = 100.0;
      49              : static const double LOADED_PIXEL_SIZE = 200.0;
      50              : static const double FONT_METRICS_DPI = 1200.0;
      51              : static constexpr double PPI = 72.0;
      52              : 
      53          785 : static int fontMetricsPixelSize(const Font& f)
      54              : {
      55          785 :     if (f.pixelSize() > 0) {
      56            0 :         return f.pixelSize();
      57              :     }
      58              : 
      59          785 :     double pixelSize = f.pointSizeF() * FONT_METRICS_DPI / PPI;
      60          785 :     return static_cast<int>(std::round(pixelSize));
      61              : }
      62              : 
      63          785 : static FaceKey faceKeyForMetricsFont(const Font& f)
      64              : {
      65          785 :     return FaceKey(dataKeyForFont(f), f.type(), fontMetricsPixelSize(f));
      66              : }
      67              : 
      68          278 : static inline RectF fromFBBox(const FBBox& bb, double scale)
      69              : {
      70          556 :     return RectF(from_f26d6(bb.left()) * scale, from_f26d6(bb.top()) * scale,
      71          834 :                  from_f26d6(bb.width()) * scale, from_f26d6(bb.height()) * scale);
      72              : }
      73              : 
      74              : static inline RectF scaleRect(const RectF& r, double scale)
      75              : {
      76              :     return RectF(r.x() * scale, r.y() * scale, r.width() * scale, r.height() * scale);
      77              : }
      78              : 
      79           21 : static const IFontFace* findSubtitutionFont(char32_t ch, const std::vector<IFontFace*>& subtitutionFaces)
      80              : {
      81           21 :     const IFontFace* founded = nullptr;
      82           22 :     for (const IFontFace* subFace : subtitutionFaces) {
      83            1 :         if (subFace->glyphIndex(ch) != 0) {
      84            1 :             founded = subFace;
      85              :         }
      86              :     }
      87           21 :     return founded;
      88              : }
      89              : 
      90          318 : static bool fitsQtGlyphCacheMetrics(const FBBox& bbox, f26dot6_t advance)
      91              : {
      92          318 :     return (bbox.width() >> 6) <= 0xFF && (bbox.height() >> 6) <= 0xFF && advance <= 0x7FFF;
      93              : }
      94              : 
      95           20 : static bool isZeroAdvanceChar(char32_t ch)
      96              : {
      97           20 :     return ch == U'\n' || ch == U'\r';
      98              : }
      99              : 
     100           20 : static bool isZeroAdvanceText(const char32_t* text, int length)
     101              : {
     102           38 :     for (int i = 0; i < length; ++i) {
     103           20 :         if (!isZeroAdvanceChar(text[i])) {
     104            2 :             return false;
     105              :         }
     106              :     }
     107           18 :     return true;
     108              : }
     109              : 
     110          682 : bool FontsEngine::RequireFace::isSymbolMode() const
     111              : {
     112          682 :     return face ? face->isSymbolMode() : false;
     113              : }
     114              : 
     115          674 : double FontsEngine::RequireFace::pixelScale() const
     116              : {
     117          674 :     return pixelScaleFor(face);
     118              : }
     119              : 
     120          791 : double FontsEngine::RequireFace::pixelScaleFor(const IFontFace* loadedFace) const
     121              : {
     122          791 :     if (!loadedFace) {
     123            0 :         return 0.0;
     124              :     }
     125              : 
     126          791 :     return static_cast<double>(requireKey.pixelSize) / static_cast<double>(loadedFace->key().pixelSize);
     127              : }
     128              : 
     129           23 : FontsEngine::~FontsEngine()
     130              : {
     131           23 :     clearLoadedFaces();
     132           23 : }
     133              : 
     134           23 : void FontsEngine::init()
     135              : {
     136           23 :     m_renderCache.init();
     137              : 
     138           23 :     fontsDatabase()->changed().onNotify(this, [this]() {
     139            7 :         clearLoadedFaces();
     140            7 :     });
     141           23 : }
     142              : 
     143            0 : void FontsEngine::setRenderCacheDirPath(const io::path_t& path, const std::string& revision)
     144              : {
     145            0 :     m_renderCache.setCacheDirPath(path, revision);
     146            0 : }
     147              : 
     148           30 : void FontsEngine::clearLoadedFaces()
     149              : {
     150          133 :     for (RequireFace* f : m_requiredFaces) {
     151          103 :         delete f;
     152              :     }
     153           30 :     m_requiredFaces.clear();
     154              : 
     155          134 :     for (IFontFace* f : m_loadedFaces) {
     156          104 :         delete f;
     157              :     }
     158           30 :     m_loadedFaces.clear();
     159           30 : }
     160              : 
     161            6 : double FontsEngine::lineSpacing(const Font& f) const
     162              : {
     163            6 :     RequireFace* rf = fontFace(f);
     164            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     165            0 :         return 0.0;
     166              :     }
     167              : 
     168            6 :     return from_f26d6(rf->face->leading() + rf->face->ascent() + rf->face->descent()) * rf->pixelScale();
     169              : }
     170              : 
     171            6 : double FontsEngine::xHeight(const Font& f) const
     172              : {
     173            6 :     RequireFace* rf = fontFace(f);
     174            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     175            0 :         return 0.0;
     176              :     }
     177              : 
     178            6 :     return from_f26d6(rf->face->xHeight()) * rf->pixelScale();
     179              : }
     180              : 
     181            6 : double FontsEngine::height(const Font& f) const
     182              : {
     183            6 :     RequireFace* rf = fontFace(f);
     184            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     185            0 :         return 0.0;
     186              :     }
     187              : 
     188            6 :     return from_f26d6(rf->face->ascent() + rf->face->descent()) * rf->pixelScale();
     189              : }
     190              : 
     191            0 : double FontsEngine::capHeight(const Font& f) const
     192              : {
     193            0 :     RequireFace* rf = fontFace(f);
     194            0 :     IF_ASSERT_FAILED(rf && rf->face) {
     195            0 :         return 0.0;
     196              :     }
     197              : 
     198            0 :     return from_f26d6(rf->face->capHeight()) * rf->pixelScale();
     199              : }
     200              : 
     201           12 : double FontsEngine::ascent(const Font& f) const
     202              : {
     203           12 :     RequireFace* rf = fontFace(f);
     204           12 :     IF_ASSERT_FAILED(rf && rf->face) {
     205            0 :         return 0.0;
     206              :     }
     207              : 
     208           12 :     return from_f26d6(rf->face->ascent()) * rf->pixelScale();
     209              : }
     210              : 
     211            6 : double FontsEngine::descent(const Font& f) const
     212              : {
     213            6 :     RequireFace* rf = fontFace(f);
     214            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     215            0 :         return 0.0;
     216              :     }
     217              : 
     218            6 :     return from_f26d6(rf->face->descent()) * rf->pixelScale();
     219              : }
     220              : 
     221            6 : double FontsEngine::underlinePos(const Font& f) const
     222              : {
     223            6 :     RequireFace* rf = fontFace(f);
     224            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     225            0 :         return 0.0;
     226              :     }
     227            6 :     return from_f26d6(rf->face->underlinePos()) * rf->pixelScale();
     228              : }
     229              : 
     230            6 : double FontsEngine::lineWidth(const Font& f) const
     231              : {
     232            6 :     RequireFace* rf = fontFace(f);
     233            6 :     IF_ASSERT_FAILED(rf && rf->face) {
     234            0 :         return 1.0;
     235              :     }
     236            6 :     return from_f26d6(rf->face->lineWidth()) * rf->pixelScale();
     237              : }
     238              : 
     239            6 : double FontsEngine::strikeOutPos(const Font& f) const
     240              : {
     241            6 :     return ascent(f) / 3.0;
     242              : }
     243              : 
     244            0 : bool FontsEngine::inFont(const Font& f, char32_t ucs4) const
     245              : {
     246            0 :     RequireFace* rf = fontFace(f);
     247            0 :     IF_ASSERT_FAILED(rf && rf->face) {
     248            0 :         return false;
     249              :     }
     250              : 
     251            0 :     return rf->face->glyphIndex(ucs4) != 0;
     252              : }
     253              : 
     254          348 : double FontsEngine::horizontalAdvance(const Font& f, const char32_t& ch) const
     255              : {
     256          348 :     RequireFace* rf = fontFace(f);
     257          348 :     IF_ASSERT_FAILED(rf && rf->face) {
     258            0 :         return 0.0;
     259              :     }
     260              : 
     261          348 :     glyph_idx_t glyphIdx = rf->face->glyphIndex(ch);
     262          348 :     return from_f26d6(rf->face->glyphAdvance(glyphIdx)) * rf->pixelScale();
     263              : }
     264              : 
     265          111 : double FontsEngine::horizontalAdvance(const Font& f, const std::u32string& text) const
     266              : {
     267          111 :     if (text.empty()) {
     268            0 :         return 0.0;
     269              :     }
     270              : 
     271          111 :     RequireFace* rf = fontFace(f);
     272          111 :     IF_ASSERT_FAILED(rf && rf->face) {
     273            0 :         return 0.0;
     274              :     }
     275              : 
     276          111 :     double advance = 0.0;
     277              : 
     278          111 :     TextBlock textBlock;
     279          111 :     textBlock.text = &text[0];
     280          111 :     textBlock.lenght = static_cast<int>(text.size());
     281              : 
     282          111 :     std::vector<FontFaceTextBlock> fontFaceBlocks = splitTextByFontFaces(rf, textBlock);
     283          234 :     for (const FontFaceTextBlock& ffBlock : fontFaceBlocks) {
     284          123 :         const IFontFace* fontFace = ffBlock.face;
     285          123 :         if (!fontFace) {
     286            8 :             if (isZeroAdvanceText(ffBlock.text.text, ffBlock.text.lenght)) {
     287            6 :                 continue;
     288              :             }
     289              : 
     290            2 :             fontFace = rf->face;
     291              :         }
     292              : 
     293          117 :         const double pixelScale = rf->pixelScaleFor(fontFace);
     294          117 :         std::vector<ShapedGlyph> glyphs = fontFace->glyphs(ffBlock.text.text, ffBlock.text.lenght);
     295          498 :         for (const ShapedGlyph& g : glyphs) {
     296          381 :             advance += from_f26d6(g.x_advance) * pixelScale;
     297              :         }
     298          117 :     }
     299              : 
     300          111 :     return advance;
     301          111 : }
     302              : 
     303          118 : RectF FontsEngine::boundingRect(const Font& f, const char32_t& ch) const
     304              : {
     305          118 :     RequireFace* rf = fontFace(f, f.type() == Font::Type::MusicSymbol);
     306          118 :     IF_ASSERT_FAILED(rf && rf->face) {
     307            0 :         return RectF();
     308              :     }
     309              : 
     310          118 :     glyph_idx_t glyphIdx = rf->face->glyphIndex(ch);
     311          118 :     return fromFBBox(rf->face->glyphBbox(glyphIdx), rf->pixelScale());
     312              : }
     313              : 
     314           48 : RectF FontsEngine::boundingRect(const Font& f, const std::u32string& text) const
     315              : {
     316           48 :     if (text.empty()) {
     317            0 :         return RectF();
     318              :     }
     319              : 
     320           48 :     RequireFace* rf = fontFace(f);
     321           48 :     IF_ASSERT_FAILED(rf && rf->face) {
     322            0 :         return RectF();
     323              :     }
     324              : 
     325           48 :     FBBox rect; // f26dot6_t units
     326           48 :     rect.setY(-rf->face->ascent());
     327           48 :     rect.setHeight(rf->face->ascent() + rf->face->descent());
     328              : 
     329           48 :     f26dot6_t xOffset = 0;
     330           48 :     f26dot6_t xmax = 0;
     331           48 :     f26dot6_t ymax = 0;
     332           48 :     bool hasGlyph = false;
     333              : 
     334           48 :     TextBlock textBlock;
     335           48 :     textBlock.text = &text[0];
     336           48 :     textBlock.lenght = static_cast<int>(text.size());
     337              : 
     338           48 :     std::vector<FontFaceTextBlock> fontFaceBlocks = splitTextByFontFaces(rf, textBlock);
     339          108 :     for (const FontFaceTextBlock& ffBlock : fontFaceBlocks) {
     340           60 :         const IFontFace* fontFace = ffBlock.face;
     341           60 :         if (!fontFace) {
     342            6 :             if (isZeroAdvanceText(ffBlock.text.text, ffBlock.text.lenght)) {
     343            6 :                 continue;
     344              :             }
     345              : 
     346            0 :             fontFace = rf->face;
     347              :         }
     348              : 
     349           54 :         std::vector<ShapedGlyph> glyphs = fontFace->glyphs(ffBlock.text.text, ffBlock.text.lenght);
     350              : 
     351          372 :         for (const ShapedGlyph& g : glyphs) {
     352          318 :             FBBox bbox = fontFace->glyphBbox(g.idx);
     353          318 :             f26dot6_t x = xOffset + bbox.x();
     354          318 :             f26dot6_t y = bbox.y();
     355              : 
     356          318 :             bool useCachedGlyphMetrics = fitsQtGlyphCacheMetrics(bbox, fontFace->glyphAdvance(g.idx));
     357          318 :             f26dot6_t glyphRight = useCachedGlyphMetrics ? ((x + 63) & -64) + bbox.width() : x + bbox.width();
     358          318 :             f26dot6_t glyphBottom = useCachedGlyphMetrics ? ((y + 63) & -64) + bbox.height() : y + bbox.height();
     359              : 
     360          318 :             if (!hasGlyph) {
     361           48 :                 rect.setX(x);
     362           48 :                 xmax = glyphRight;
     363           48 :                 ymax = glyphBottom;
     364           48 :                 hasGlyph = true;
     365              :             } else {
     366          270 :                 rect.setX(std::min(rect.x(), x));
     367          270 :                 xmax = std::max(xmax, glyphRight);
     368          270 :                 ymax = std::max(ymax, glyphBottom);
     369              :             }
     370              : 
     371          318 :             rect.setY(std::min(rect.y(), y));
     372          318 :             xOffset += g.x_advance;
     373              :         }
     374           54 :     }
     375              : 
     376           48 :     if (!hasGlyph) {
     377            0 :         rect.setX(0);
     378            0 :         rect.setWidth(0);
     379            0 :         return fromFBBox(rect, rf->pixelScale());
     380              :     }
     381              : 
     382           48 :     rect.setWidth(xmax - rect.x());
     383           48 :     rect.setHeight(std::max(rect.height(), ymax - rect.y()));
     384              : 
     385           48 :     return fromFBBox(rect, rf->pixelScale());
     386           48 : }
     387              : 
     388          112 : RectF FontsEngine::tightBoundingRect(const Font& f, const std::u32string& text) const
     389              : {
     390          112 :     if (text.empty()) {
     391            0 :         return RectF();
     392              :     }
     393              : 
     394          112 :     RequireFace* rf = fontFace(f);
     395          112 :     IF_ASSERT_FAILED(rf && rf->face) {
     396            0 :         return RectF();
     397              :     }
     398              : 
     399          112 :     FBBox rect; // f26dot6_t units
     400          112 :     f26dot6_t xOffset = 0;
     401          112 :     f26dot6_t xmax = 0;
     402          112 :     f26dot6_t ymax = 0;
     403          112 :     bool hasGlyph = false;
     404              : 
     405          112 :     TextBlock textBlock;
     406          112 :     textBlock.text = &text[0];
     407          112 :     textBlock.lenght = static_cast<int>(text.size());
     408              : 
     409          112 :     std::vector<FontFaceTextBlock> fontFaceBlocks = splitTextByFontFaces(rf, textBlock);
     410          236 :     for (const FontFaceTextBlock& ffBlock : fontFaceBlocks) {
     411          124 :         const IFontFace* fontFace = ffBlock.face;
     412          124 :         if (!fontFace) {
     413            6 :             if (isZeroAdvanceText(ffBlock.text.text, ffBlock.text.lenght)) {
     414            6 :                 continue;
     415              :             }
     416              : 
     417            0 :             fontFace = rf->face;
     418              :         }
     419              : 
     420          118 :         std::vector<ShapedGlyph> glyphs = fontFace->glyphs(ffBlock.text.text, ffBlock.text.lenght);
     421              : 
     422          560 :         for (const ShapedGlyph& g : glyphs) {
     423          442 :             FBBox bbox = fontFace->glyphBbox(g.idx);
     424          442 :             f26dot6_t x = xOffset + bbox.x();
     425          442 :             f26dot6_t y = bbox.y();
     426              : 
     427          442 :             f26dot6_t glyphRight = ((x + 63) & -64) + bbox.width();
     428          442 :             f26dot6_t glyphBottom = ((y + 63) & -64) + bbox.height();
     429              : 
     430          442 :             if (!hasGlyph) {
     431          112 :                 rect.setX(x);
     432          112 :                 rect.setY(y);
     433          112 :                 xmax = glyphRight;
     434          112 :                 ymax = glyphBottom;
     435          112 :                 hasGlyph = true;
     436              :             } else {
     437          330 :                 rect.setX(std::min(rect.x(), x));
     438          330 :                 rect.setY(std::min(rect.y(), y));
     439          330 :                 xmax = std::max(xmax, glyphRight);
     440          330 :                 ymax = std::max(ymax, glyphBottom);
     441              :             }
     442              : 
     443          442 :             xOffset += g.x_advance;
     444              :         }
     445          118 :     }
     446              : 
     447          112 :     if (!hasGlyph) {
     448            0 :         return RectF();
     449              :     }
     450              : 
     451          112 :     rect.setWidth(xmax - rect.x());
     452          112 :     rect.setHeight(ymax - rect.y());
     453              : 
     454          112 :     return fromFBBox(rect, rf->pixelScale());
     455          112 : }
     456              : 
     457            0 : std::vector<GlyphImage> FontsEngine::render(const Font& f, const std::u32string& text) const
     458              : {
     459              :     //! NOTE for rendering, all fonts, including symbols fonts, are processed as text
     460            0 :     RequireFace* rf = fontFace(f);
     461            0 :     IF_ASSERT_FAILED(rf && rf->face) {
     462            0 :         return std::vector<GlyphImage>();
     463              :     }
     464              : 
     465            0 :     std::vector<GlyphImage> images;
     466              : 
     467            0 :     if (text.empty()) {
     468            0 :         return images;
     469              :     }
     470              : 
     471              : #ifndef MUSE_MODULE_DRAW_USE_QTTEXTDRAW
     472              :     double glyphLeft = 0;
     473              : 
     474              :     TextBlock textBlock;
     475              :     textBlock.text = &text[0];
     476              :     textBlock.lenght = static_cast<int>(text.size());
     477              : 
     478              :     std::vector<FontFaceTextBlock> fontFaceBlocks = splitTextByFontFaces(rf, textBlock);
     479              :     for (const FontFaceTextBlock& ffBlock : fontFaceBlocks) {
     480              :         const IFontFace* layoutFace = ffBlock.face;
     481              :         if (!layoutFace) {
     482              :             if (isZeroAdvanceText(ffBlock.text.text, ffBlock.text.lenght)) {
     483              :                 continue;
     484              :             }
     485              : 
     486              :             layoutFace = rf->face;
     487              :         }
     488              : 
     489              :         const IFontFace* sdfFace = sdfFontFaceFor(layoutFace);
     490              :         if (!sdfFace) {
     491              :             //! NOTE Fall back to the layout face itself rather than dropping this run's glyphs
     492              :             sdfFace = layoutFace;
     493              :         }
     494              : 
     495              :         double layoutScale = rf->pixelScaleFor(layoutFace);
     496              :         double sdfToLayoutScale = rf->pixelScaleFor(sdfFace);
     497              :         std::vector<ShapedGlyph> glyphs = layoutFace->glyphs(ffBlock.text.text, ffBlock.text.lenght);
     498              : 
     499              :         for (const ShapedGlyph& g : glyphs) {
     500              :             if (!layoutFace->glyphBbox(g.idx).isEmpty()) {
     501              :                 GlyphImage image = m_renderCache.load(sdfFace->key(), g.idx);
     502              :                 if (image.isNull()) {
     503              :                     image = sdfFace->glyphImage(g.idx);
     504              :                     m_renderCache.store(sdfFace->key(), g.idx, image);
     505              :                 }
     506              : 
     507              :                 image.rect = scaleRect(image.rect, sdfToLayoutScale);
     508              :                 image.rect.translate(glyphLeft, 0);
     509              : 
     510              :                 images.push_back(std::move(image));
     511              :             }
     512              : 
     513              :             glyphLeft += from_f26d6(g.x_advance) * layoutScale;
     514              :         }
     515              :     }
     516              : #endif
     517              : 
     518            0 :     return images;
     519            0 : }
     520              : 
     521            0 : void FontsEngine::setFontFaceFactory(const FontFaceFactory& f)
     522              : {
     523            0 :     m_fontFaceFactory = f;
     524            0 : }
     525              : 
     526          104 : IFontFace* FontsEngine::createFontFace(const FontData& fontData, Font::Type type) const
     527              : {
     528          104 :     const FontDataKey& dataKey = fontData.key;
     529          104 :     if (m_fontFaceFactory) {
     530            0 :         return m_fontFaceFactory(dataKey, type);
     531              :     }
     532              : 
     533          104 :     IFontFace* origin = nullptr;
     534          104 :     if (isFtx(fontData.data)) {
     535              : #ifdef MUSE_MODULE_DRAW_USE_FONTFACE_XT
     536            0 :         origin = new FontFaceXT();
     537              : #else
     538              :         LOGE() << "XT font face backend is disabled: " << dataKey.family().id();
     539              :         return nullptr;
     540              : #endif
     541              :     } else {
     542              : #ifdef MUSE_MODULE_DRAW_USE_FONTFACE_FT
     543          104 :         origin = new FontFaceFT();
     544              : #else
     545              :         LOGE() << "FreeType font face backend is disabled: " << dataKey.family().id();
     546              :         return nullptr;
     547              : #endif
     548              :     }
     549              : 
     550          104 :     return new FontFaceDU(origin);
     551              : }
     552              : 
     553          104 : IFontFace* FontsEngine::fontFaceByActualDataKey(const FontDataKey& actualDataKey, Font::Type type, int loadedPixelSize,
     554              :                                                 bool isSymbolMode) const
     555              : {
     556          345 :     for (IFontFace* face : m_loadedFaces) {
     557          481 :         if (face->key().dataKey == actualDataKey && face->key().type == type && face->key().pixelSize == loadedPixelSize
     558          481 :             && face->isSymbolMode() == isSymbolMode) {
     559            0 :             return face;
     560              :         }
     561              :     }
     562              : 
     563          104 :     FontData fontData = fontsDatabase()->fontData(actualDataKey, type);
     564          104 :     if (!fontData.valid()) {
     565            0 :         LOGE() << "font data is empty: " << actualDataKey.family().id();
     566            0 :         return nullptr;
     567              :     }
     568              : 
     569          104 :     FaceKey loadedKey;
     570          104 :     loadedKey.dataKey = fontData.key;
     571          104 :     loadedKey.type = type;
     572          104 :     loadedKey.pixelSize = loadedPixelSize;
     573              : 
     574          104 :     IFontFace* face = createFontFace(fontData, type);
     575          104 :     IF_ASSERT_FAILED(face) {
     576            0 :         return nullptr;
     577              :     }
     578              : 
     579          104 :     if (!face->load(loadedKey, fontData, isSymbolMode)) {
     580            0 :         LOGE() << "failed load font face: " << fontData.key.family().id();
     581            0 :         delete face;
     582            0 :         return nullptr;
     583              :     }
     584              : 
     585          104 :     m_loadedFaces.push_back(face);
     586          104 :     return face;
     587          104 : }
     588              : 
     589            0 : IFontFace* FontsEngine::sdfFontFaceFor(const IFontFace* layoutFace) const
     590              : {
     591            0 :     if (!layoutFace) {
     592            0 :         return nullptr;
     593              :     }
     594              : 
     595            0 :     return fontFaceByActualDataKey(layoutFace->key().dataKey, layoutFace->key().type, static_cast<int>(LOADED_PIXEL_SIZE),
     596            0 :                                    layoutFace->isSymbolMode());
     597              : }
     598              : 
     599          785 : FontsEngine::RequireFace* FontsEngine::fontFace(const Font& f, bool isSymbolMode) const
     600              : {
     601              :     //! NOTE This font is required
     602          785 :     FaceKey requireKey = faceKeyForMetricsFont(f);
     603              : 
     604              :     //! NOTE If pixelSize is not set, then specify the default
     605              :     //! (this is the default pixelSize in Qt)
     606          785 :     if (!(requireKey.pixelSize > 0)) {
     607            0 :         requireKey.pixelSize = DEFAULT_PIXEL_SIZE;
     608              :     }
     609              : 
     610              :     //! NOTE At the moment, in some cases, the type may not be specified,
     611              :     //! so set as Text
     612          785 :     if (requireKey.type == Font::Type::Undefined || requireKey.type == Font::Type::Unknown) {
     613            0 :         requireKey.type = Font::Type::Text;
     614              :     }
     615              : 
     616              :     //! NOTE We are looking for the require font we need among the previously loaded ones
     617         2450 :     for (RequireFace* face : m_requiredFaces) {
     618         2347 :         if (face->requireKey == requireKey && face->isSymbolMode() == isSymbolMode) {
     619          682 :             return face;
     620              :         }
     621              :     }
     622              : 
     623              :     //! Let's find out which real font will be used
     624              :     //! (for example, if there is no required one)
     625          103 :     FontDataKey actualDataKey = fontsDatabase()->actualFont(requireKey.dataKey, requireKey.type);
     626              : 
     627          103 :     const int loadedPixelSize = isFtx(fontsDatabase()->fontData(actualDataKey, requireKey.type).data)
     628          103 :                                 ? static_cast<int>(LOADED_PIXEL_SIZE)
     629          103 :                                 : requireKey.pixelSize;
     630          103 :     IFontFace* face = fontFaceByActualDataKey(actualDataKey, requireKey.type, loadedPixelSize, isSymbolMode);
     631          103 :     if (!face) {
     632            0 :         return nullptr;
     633              :     }
     634              : 
     635              :     //! If we didn't find it, we create a new require font
     636          103 :     RequireFace* newFont = new RequireFace();
     637          103 :     newFont->requireKey = requireKey;
     638          103 :     newFont->actualDataKey = actualDataKey;
     639          103 :     newFont->face = face;
     640              : 
     641          103 :     auto subtitutionFontDataKeys = fontsDatabase()->substitutionFonts(requireKey.dataKey);
     642          104 :     for (const FontDataKey& dataKey : subtitutionFontDataKeys) {
     643            1 :         const FontDataKey actualSubtitutionDataKey = fontsDatabase()->actualFont(dataKey, requireKey.type);
     644            1 :         const int subtitutionLoadedPixelSize = isFtx(fontsDatabase()->fontData(actualSubtitutionDataKey, requireKey.type).data)
     645            1 :                                                ? static_cast<int>(LOADED_PIXEL_SIZE) : requireKey.pixelSize;
     646            1 :         IFontFace* subtitutionFace = fontFaceByActualDataKey(actualSubtitutionDataKey, requireKey.type, subtitutionLoadedPixelSize,
     647            1 :                                                              isSymbolMode);
     648            1 :         if (subtitutionFace) {
     649            1 :             newFont->subtitutionFaces.push_back(subtitutionFace);
     650              :         }
     651            1 :     }
     652              : 
     653          103 :     m_requiredFaces.push_back(newFont);
     654              : 
     655          103 :     return newFont;
     656          785 : }
     657              : 
     658          271 : std::vector<FontsEngine::FontFaceTextBlock> FontsEngine::splitTextByFontFaces(const RequireFace* rf, const TextBlock& text) const
     659              : {
     660          271 :     std::vector<FontFaceTextBlock> textBlocks;
     661              : 
     662          271 :     FontFaceTextBlock txtBlock;
     663          271 :     txtBlock.text.text = &text.text[0];
     664          271 :     const IFontFace* current = nullptr;
     665         1430 :     for (int i = 0; i < text.lenght; ++i) {
     666         1159 :         const IFontFace* newFace = nullptr;
     667         1159 :         if (rf->face->glyphIndex(text.text[i]) != 0) {
     668         1138 :             newFace = rf->face;
     669              :         } else {
     670           21 :             newFace = findSubtitutionFont(text.text[i], rf->subtitutionFaces);
     671              :         }
     672              : 
     673         1159 :         if (txtBlock.text.lenght > 0 && newFace != current) {
     674           36 :             txtBlock.face = current;
     675           36 :             textBlocks.push_back(txtBlock);
     676           36 :             txtBlock.text.text = &text.text[i];
     677           36 :             txtBlock.text.lenght = 0;
     678              :         }
     679              : 
     680         1159 :         current = newFace;
     681         1159 :         ++txtBlock.text.lenght;
     682              : 
     683         1159 :         if (i == (text.lenght - 1)) {
     684          271 :             txtBlock.face = current;
     685          271 :             textBlocks.push_back(txtBlock);
     686          271 :             txtBlock.text.text = nullptr;
     687          271 :             txtBlock.text.lenght = 0;
     688              :         }
     689              :     }
     690              : 
     691          271 :     return textBlocks;
     692            0 : }
        

Generated by: LCOV version 2.0-1