LCOV - code coverage report
Current view: top level - core/font - SPFontFace.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 289 446 64.8 %
Date: 2024-05-12 00:16:13 Functions: 29 38 76.3 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 2023-2024 Stappler LLC <admin@stappler.dev>
       3             : 
       4             :  Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  of this software and associated documentation files (the "Software"), to deal
       6             :  in the Software without restriction, including without limitation the rights
       7             :  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  copies of the Software, and to permit persons to whom the Software is
       9             :  furnished to do so, subject to the following conditions:
      10             : 
      11             :  The above copyright notice and this permission notice shall be included in
      12             :  all copies or substantial portions of the Software.
      13             : 
      14             :  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
      20             :  THE SOFTWARE.
      21             :  **/
      22             : 
      23             : #include "SPFontFace.h"
      24             : #include "SPFontLibrary.h"
      25             : 
      26             : #include "ft2build.h"
      27             : #include FT_FREETYPE_H
      28             : #include FT_GLYPH_H
      29             : #include FT_MULTIPLE_MASTERS_H
      30             : #include FT_TRUETYPE_TABLES_H
      31             : #include FT_SFNT_NAMES_H
      32             : #include FT_ADVANCES_H
      33             : 
      34             : namespace STAPPLER_VERSIONIZED stappler::font {
      35             : 
      36      381070 : static constexpr uint32_t getAxisTag(char c1, char c2, char c3, char c4) {
      37      381070 :         return uint32_t(c1 & 0xFF) << 24 | uint32_t(c2 & 0xFF) << 16 | uint32_t(c3 & 0xFF) << 8 | uint32_t(c4 & 0xFF);
      38             : }
      39             : 
      40      381070 : static constexpr uint32_t getAxisTag(const char c[4]) {
      41      381070 :         return getAxisTag(c[0], c[1], c[2], c[3]);
      42             : }
      43             : 
      44           0 : static CharGroupId getCharGroupForChar(char16_t c) {
      45             :         using namespace chars;
      46           0 :         if (CharGroup<char16_t, CharGroupId::Numbers>::match(c)) {
      47           0 :                 return CharGroupId::Numbers;
      48           0 :         } else if (CharGroup<char16_t, CharGroupId::Latin>::match(c)) {
      49           0 :                 return CharGroupId::Latin;
      50           0 :         } else if (CharGroup<char16_t, CharGroupId::Cyrillic>::match(c)) {
      51           0 :                 return CharGroupId::Cyrillic;
      52           0 :         } else if (CharGroup<char16_t, CharGroupId::Currency>::match(c)) {
      53           0 :                 return CharGroupId::Currency;
      54           0 :         } else if (CharGroup<char16_t, CharGroupId::GreekBasic>::match(c)) {
      55           0 :                 return CharGroupId::GreekBasic;
      56           0 :         } else if (CharGroup<char16_t, CharGroupId::Math>::match(c)) {
      57           0 :                 return CharGroupId::Math;
      58           0 :         } else if (CharGroup<char16_t, CharGroupId::TextPunctuation>::match(c)) {
      59           0 :                 return CharGroupId::TextPunctuation;
      60             :         }
      61           0 :         return CharGroupId::None;
      62             : }
      63             : 
      64          50 : bool FontFaceData::init(StringView name, BytesView data, bool persistent) {
      65          50 :         if (persistent) {
      66          50 :                 _view = data;
      67          50 :                 _persistent = true;
      68          50 :                 _name = name.str<Interface>();
      69          50 :                 return true;
      70             :         } else {
      71           0 :                 return init(name, data.bytes<Interface>());
      72             :         }
      73             : }
      74             : 
      75           0 : bool FontFaceData::init(StringView name, Bytes &&data) {
      76           0 :         _persistent = false;
      77           0 :         _data = move(data);
      78           0 :         _view = _data;
      79           0 :         _name = name.str<Interface>();
      80           0 :         return true;
      81             : }
      82             : 
      83         148 : bool FontFaceData::init(StringView name, Function<Bytes()> &&cb) {
      84         148 :         _persistent = true;
      85         148 :         _data = cb();
      86         150 :         _view = _data;
      87         150 :         _name = name.str<Interface>();
      88         150 :         return true;
      89             : }
      90             : 
      91          50 : FontLayoutParameters FontFaceData::acquireDefaultParams(FT_Face face) {
      92          50 :         FontLayoutParameters sfnt;
      93             : 
      94          50 :         if (face->style_flags & FT_STYLE_FLAG_ITALIC) {
      95           0 :                 sfnt.fontStyle = FontStyle::Italic;
      96             :         }
      97             : 
      98          50 :         if (face->style_flags & FT_STYLE_FLAG_BOLD) {
      99           0 :                 sfnt.fontWeight = FontWeight::Bold;
     100             :         }
     101             : 
     102          50 :         auto table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
     103          50 :         if (table) {
     104          50 :                 sfnt.fontWeight = FontWeight(table->usWeightClass);
     105          50 :                 switch (table->usWidthClass) {
     106           0 :                 case 1: sfnt.fontStretch = FontStretch::UltraCondensed; break;
     107           0 :                 case 2: sfnt.fontStretch = FontStretch::ExtraCondensed; break;
     108           0 :                 case 3: sfnt.fontStretch = FontStretch::Condensed; break;
     109           0 :                 case 4: sfnt.fontStretch = FontStretch::SemiCondensed; break;
     110          50 :                 case 5: sfnt.fontStretch = FontStretch::Normal; break;
     111           0 :                 case 6: sfnt.fontStretch = FontStretch::SemiExpanded; break;
     112           0 :                 case 7: sfnt.fontStretch = FontStretch::Expanded; break;
     113           0 :                 case 8: sfnt.fontStretch = FontStretch::ExtraExpanded; break;
     114           0 :                 case 9: sfnt.fontStretch = FontStretch::UltraExpanded; break;
     115           0 :                 default: break;
     116             :                 }
     117             : 
     118          50 :                 if (table->panose[0] == 2) {
     119             :                         // only for Latin Text
     120          50 :                         FontLayoutParameters panose;
     121          50 :                         switch (table->panose[2]) {
     122           0 :                         case 2: panose.fontWeight = FontWeight::ExtraLight; break;
     123           0 :                         case 3: panose.fontWeight = FontWeight::Light; break;
     124           0 :                         case 4: panose.fontWeight = FontWeight::Thin; break;
     125           0 :                         case 5: panose.fontWeight = FontWeight::Normal; break;
     126          50 :                         case 6: panose.fontWeight = FontWeight::Medium; break;
     127           0 :                         case 7: panose.fontWeight = FontWeight::SemiBold; break;
     128           0 :                         case 8: panose.fontWeight = FontWeight::Bold; break;
     129           0 :                         case 9: panose.fontWeight = FontWeight::ExtraBold; break;
     130           0 :                         case 10: panose.fontWeight = FontWeight::Heavy; break;
     131           0 :                         case 11: panose.fontWeight = FontWeight::Black; break;
     132           0 :                         default: break;
     133             :                         }
     134             : 
     135          50 :                         switch (table->panose[3]) {
     136           0 :                         case 2: panose.fontStretch = FontStretch::Normal; break;
     137           0 :                         case 5: panose.fontStretch = FontStretch::Expanded; break;
     138           0 :                         case 6: panose.fontStretch = FontStretch::Condensed; break;
     139           0 :                         case 7: panose.fontStretch = FontStretch::ExtraExpanded; break;
     140           0 :                         case 8: panose.fontStretch = FontStretch::ExtraCondensed; break;
     141          50 :                         default: break;
     142             :                         }
     143             : 
     144          50 :                         switch (table->panose[7]) {
     145           0 :                         case 5: panose.fontStyle = FontStyle::Oblique; break;
     146           0 :                         case 9: panose.fontStyle = FontStyle::Oblique; break;
     147           0 :                         case 10: panose.fontStyle = FontStyle::Oblique; break;
     148           0 :                         case 11: panose.fontStyle = FontStyle::Oblique; break;
     149           0 :                         case 12: panose.fontStyle = FontStyle::Oblique; break;
     150           0 :                         case 13: panose.fontStyle = FontStyle::Oblique; break;
     151           0 :                         case 14: panose.fontStyle = FontStyle::Oblique; break;
     152          50 :                         default: break;
     153             :                         }
     154             : 
     155          50 :                         if (panose.fontWeight != sfnt.fontWeight) {
     156          50 :                                 if (panose.fontWeight != FontWeight::Normal) {
     157          50 :                                         sfnt.fontWeight = panose.fontWeight;
     158             :                                 }
     159             :                         }
     160             : 
     161          50 :                         if (panose.fontStretch != sfnt.fontStretch) {
     162           0 :                                 if (panose.fontStretch != FontStretch::Normal) {
     163           0 :                                         sfnt.fontStretch = panose.fontStretch;
     164             :                                 }
     165             :                         }
     166             : 
     167          50 :                         if (sfnt.fontStyle == FontStyle::Normal && panose.fontStyle != sfnt.fontStyle) {
     168           0 :                                 sfnt.fontStyle = panose.fontStyle;
     169             :                         }
     170             :                 }
     171             :         } else {
     172           0 :                 log::error("font::FontFaceData", "No preconfigured style or OS/2 table for font: ", _name);
     173             :         }
     174          50 :         return sfnt;
     175             : }
     176             : 
     177         200 : void FontFaceData::inspectVariableFont(FontLayoutParameters params, FT_Library lib, FT_Face face) {
     178         200 :         FT_MM_Var *masters = nullptr;
     179         200 :         FT_Get_MM_Var(face, &masters);
     180             : 
     181         200 :         _variations.weight = params.fontWeight;
     182         200 :         _variations.stretch = params.fontStretch;
     183         200 :         _variations.opticalSize = uint32_t(0);
     184         200 :         _variations.italic = uint32_t(params.fontStyle == FontStyle::Italic ? 1 : 0);
     185         200 :         _variations.slant = params.fontStyle;
     186         200 :         _variations.grade = params.fontGrade;
     187             : 
     188         200 :         if (masters) {
     189         900 :                 for (FT_UInt i = 0; i < masters->num_axis; ++ i) {
     190         750 :                         auto tag = masters->axis[i].tag;
     191         750 :                         if (tag == getAxisTag("wght")) {
     192         150 :                                 _variations.axisMask |= FontVariableAxis::Weight;
     193         150 :                                 _variations.weight.min = FontWeight(masters->axis[i].minimum >> 16);
     194         150 :                                 _variations.weight.max = FontWeight(masters->axis[i].maximum >> 16);
     195         600 :                         } else if (tag == getAxisTag("wdth")) {
     196          50 :                                 _variations.axisMask |= FontVariableAxis::Width;
     197          50 :                                 _variations.stretch.min = FontStretch(masters->axis[i].minimum >> 15);
     198          50 :                                 _variations.stretch.max = FontStretch(masters->axis[i].maximum >> 15);
     199         550 :                         } else if (tag == getAxisTag("ital")) {
     200           0 :                                 _variations.axisMask |= FontVariableAxis::Italic;
     201           0 :                                 _variations.italic.min = masters->axis[i].minimum;
     202           0 :                                 _variations.italic.max = masters->axis[i].maximum;
     203         550 :                         } else if (tag == getAxisTag("slnt")) {
     204          50 :                                 _variations.axisMask |= FontVariableAxis::Slant;
     205          50 :                                 _variations.slant.min = FontStyle(masters->axis[i].minimum >> 10);
     206          50 :                                 _variations.slant.max = FontStyle(masters->axis[i].maximum >> 10);
     207         500 :                         } else if (tag == getAxisTag("opsz")) {
     208          50 :                                 _variations.axisMask |= FontVariableAxis::OpticalSize;
     209          50 :                                 _variations.opticalSize.min = masters->axis[i].minimum;
     210          50 :                                 _variations.opticalSize.max = masters->axis[i].maximum;
     211         450 :                         } else if (tag == getAxisTag("GRAD")) {
     212          50 :                                 _variations.axisMask |= FontVariableAxis::Grade;
     213          50 :                                 _variations.grade.min = FontGrade(masters->axis[i].minimum >> 16);
     214          50 :                                 _variations.grade.max = FontGrade(masters->axis[i].maximum >> 16);
     215             :                         }
     216             :                         /* std::cout << "Variable axis: [" << masters->axis[i].tag << "] "
     217             :                                         << (masters->axis[i].minimum >> 16) << " - " << (masters->axis[i].maximum >> 16)
     218             :                                         << " def: "<< (masters->axis[i].def >> 16) << "\n"; */
     219             :                 }
     220             : 
     221         150 :                 FT_Done_MM_Var(lib, masters);
     222             :         }
     223             : 
     224         200 :         _params = params;
     225         200 : }
     226             : 
     227        6916 : BytesView FontFaceData::getView() const {
     228        6916 :         return _view;
     229             : }
     230             : 
     231        5724 : FontSpecializationVector FontFaceData::getSpecialization(const FontSpecializationVector &vec) const {
     232        5724 :         return _variations.getSpecialization(vec);
     233             : }
     234             : 
     235       13432 : FontFaceObject::~FontFaceObject() { }
     236             : 
     237        6716 : bool FontFaceObject::init(StringView name, const Rc<FontFaceData> &data, FT_Library lib, FT_Face face, const FontSpecializationVector &spec, uint16_t id) {
     238        6716 :         auto err = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
     239        6716 :         if (err != FT_Err_Ok) {
     240           0 :                 return false;
     241             :         }
     242             : 
     243        6716 :         auto &var = data->getVariations();
     244        6716 :         if (var.axisMask != FontVariableAxis::None) {
     245        5870 :                 Vector<FT_Fixed> vector;
     246             : 
     247             :                 FT_MM_Var *masters;
     248        5870 :                 FT_Get_MM_Var(face, &masters);
     249             : 
     250        5870 :                 if (masters) {
     251       80380 :                         for (FT_UInt i = 0; i < masters->num_axis; ++ i) {
     252       74510 :                                 auto tag = masters->axis[i].tag;
     253       74510 :                                 if (tag == getAxisTag("wght")) {
     254        5870 :                                         vector.emplace_back(var.weight.clamp(spec.fontWeight).get() << 16);
     255       68640 :                                 } else if (tag == getAxisTag("wdth")) {
     256        5720 :                                         vector.emplace_back(var.stretch.clamp(spec.fontStretch).get() << 15);
     257       62920 :                                 } else if (tag == getAxisTag("ital")) {
     258           0 :                                         if (spec.fontStyle.get() == FontStyle::Normal.get()) {
     259           0 :                                                 vector.emplace_back(var.italic.min);
     260           0 :                                         } else if (spec.fontStyle.get() == FontStyle::Italic.get()) {
     261           0 :                                                 vector.emplace_back(var.italic.max);
     262             :                                         } else {
     263           0 :                                                 if ((var.axisMask & FontVariableAxis::Slant) != FontVariableAxis::None) {
     264           0 :                                                         vector.emplace_back(var.italic.min); // has true oblique
     265             :                                                 } else {
     266           0 :                                                         vector.emplace_back(var.italic.max);
     267             :                                                 }
     268             :                                         }
     269       62920 :                                 } else if (tag == getAxisTag("slnt")) {
     270        5720 :                                         if (spec.fontStyle.get() == FontStyle::Normal.get()) {
     271        1865 :                                                 vector.emplace_back(0);
     272        3855 :                                         } else if (spec.fontStyle.get() == FontStyle::Italic.get()) {
     273           0 :                                                 if ((var.axisMask & FontVariableAxis::Italic) != FontVariableAxis::None) {
     274           0 :                                                         vector.emplace_back(masters->axis[i].def);
     275             :                                                 } else {
     276           0 :                                                         vector.emplace_back(var.slant.clamp(FontStyle::Oblique).get() << 10);
     277             :                                                 }
     278             :                                         } else {
     279        3855 :                                                 vector.emplace_back(var.slant.clamp(spec.fontStyle).get() << 10);
     280             :                                         }
     281       57200 :                                 } else if (tag == getAxisTag("opsz")) {
     282        5720 :                                         auto opticalSize = uint32_t(floorf(spec.fontSize.get() / spec.density)) << 16;
     283        5720 :                                         vector.emplace_back(var.opticalSize.clamp(opticalSize));
     284       51480 :                                 } else if (tag == getAxisTag("GRAD")) {
     285        5720 :                                         vector.emplace_back(var.grade.clamp(spec.fontGrade).get() << 16);
     286             :                                 } else {
     287       45760 :                                         vector.emplace_back(masters->axis[i].def);
     288             :                                 }
     289             :                         }
     290             : 
     291        5870 :                         FT_Set_Var_Design_Coordinates(face, vector.size(), vector.data());
     292        5870 :                         FT_Done_MM_Var(lib, masters);
     293             :                 }
     294        5870 :         }
     295             : 
     296             :         // set the requested font size
     297        6716 :         err = FT_Set_Pixel_Sizes(face, spec.fontSize.get(), spec.fontSize.get());
     298        6716 :         if (err != FT_Err_Ok) {
     299           0 :                 return false;
     300             :         }
     301             : 
     302        6716 :         _spec = spec;
     303        6716 :         _metrics.size = spec.fontSize.get();
     304        6716 :         _metrics.height = face->size->metrics.height >> 6;
     305        6716 :         _metrics.ascender = face->size->metrics.ascender >> 6;
     306        6716 :         _metrics.descender = face->size->metrics.descender >> 6;
     307        6716 :         _metrics.underlinePosition = face->underline_position >> 6;
     308        6716 :         _metrics.underlineThickness = face->underline_thickness >> 6;
     309             : 
     310        6716 :         _name = name.str<Interface>();
     311        6716 :         _id = id;
     312        6716 :         _data = data;
     313        6716 :         _face = face;
     314             : 
     315        6716 :         return true;
     316             : }
     317             : 
     318           0 : bool FontFaceObject::acquireTexture(char32_t theChar, const Callback<void(const CharTexture &)> &cb) {
     319           0 :         std::unique_lock lock(_faceMutex);
     320             : 
     321           0 :         return acquireTextureUnsafe(theChar, cb);
     322           0 : }
     323             : 
     324      149310 : bool FontFaceObject::acquireTextureUnsafe(char32_t theChar, const Callback<void(const CharTexture &)> &cb) {
     325      149310 :         int glyph_index = FT_Get_Char_Index(_face, theChar);
     326      149701 :         if (!glyph_index) {
     327           0 :                 return false;
     328             :         }
     329             : 
     330      149701 :         auto err = FT_Load_Glyph(_face, glyph_index, FT_LOAD_DEFAULT | FT_LOAD_RENDER);
     331      150152 :         if (err != FT_Err_Ok) {
     332           0 :                 return false;
     333             :         }
     334             : 
     335             :         //log::format("Texture", "%s: %d '%s'", data.layout->getName().c_str(), theChar.charID, string::toUtf8(theChar.charID).c_str());
     336             : 
     337      150152 :         if (_face->glyph->bitmap.buffer != nullptr) {
     338      150152 :                 if (_face->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
     339           0 :                         cb(CharTexture{theChar,
     340      150158 :                                 static_cast<int16_t>(_face->glyph->metrics.horiBearingX >> 6),
     341      150158 :                                 static_cast<int16_t>(- (_face->glyph->metrics.horiBearingY >> 6)),
     342      150158 :                                 static_cast<uint16_t>(_face->glyph->metrics.width >> 6),
     343      150158 :                                 static_cast<uint16_t>(_face->glyph->metrics.height >> 6),
     344      150158 :                                 static_cast<uint16_t>(_face->glyph->bitmap.width),
     345      150158 :                                 static_cast<uint16_t>(_face->glyph->bitmap.rows),
     346      150158 :                                 _face->glyph->bitmap.pitch ? int16_t(_face->glyph->bitmap.pitch) : int16_t(_face->glyph->bitmap.width),
     347      150158 :                                 _id,
     348      150158 :                                 _face->glyph->bitmap.buffer
     349             :                         });
     350      150303 :                         return true;
     351             :                 }
     352             :         } else {
     353           0 :                 if (!chars::isspace(theChar) && theChar != char16_t(0x0A)) {
     354           0 :                         log::format(log::Warn, "Font", "error: no bitmap for (%d) '%s'", theChar, string::toUtf8<Interface>(theChar).data());
     355             :                 }
     356             :         }
     357           0 :         return false;
     358             : }
     359             : 
     360       30366 : bool FontFaceObject::addChars(const Vector<char32_t> &chars, bool expand, Vector<char32_t> *failed) {
     361       30366 :         bool updated = false;
     362       30366 :         uint32_t mask = 0;
     363             : 
     364             :         if constexpr (!config::FontPreloadGroups) {
     365       30366 :                 expand = false;
     366             :         }
     367             : 
     368             :         // for some chars, we add full group, not only requested char
     369      537488 :         for (auto &c : chars) {
     370      507122 :                 if (expand) {
     371           0 :                         auto g = getCharGroupForChar(c);
     372           0 :                         if (g != CharGroupId::None) {
     373           0 :                                 if ((mask & toInt(g)) == 0) {
     374           0 :                                         mask |= toInt(g);
     375           0 :                                         if (addCharGroup(g, failed)) {
     376           0 :                                                 updated = true;
     377             :                                         }
     378           0 :                                         continue;
     379             :                                 }
     380             :                         }
     381             :                 }
     382             : 
     383      507122 :                 if (!addChar(c, updated) && failed) {
     384       25306 :                         mem_std::emplace_ordered(*failed, c);
     385             :                 }
     386             :         }
     387       30366 :         return updated;
     388             : }
     389             : 
     390           0 : bool FontFaceObject::addCharGroup(CharGroupId g, Vector<char32_t> *failed) {
     391           0 :         bool updated = false;
     392             :         using namespace chars;
     393           0 :         auto f = [&, this] (char32_t c) {
     394           0 :                 if (!addChar(c, updated) && failed) {
     395           0 :                         mem_std::emplace_ordered(*failed, c);
     396             :                 }
     397           0 :         };
     398             : 
     399           0 :         switch (g) {
     400           0 :         case CharGroupId::Numbers: CharGroup<char32_t, CharGroupId::Numbers>::foreach(f); break;
     401           0 :         case CharGroupId::Latin: CharGroup<char32_t, CharGroupId::Latin>::foreach(f); break;
     402           0 :         case CharGroupId::Cyrillic: CharGroup<char32_t, CharGroupId::Cyrillic>::foreach(f); break;
     403           0 :         case CharGroupId::Currency: CharGroup<char32_t, CharGroupId::Currency>::foreach(f); break;
     404           0 :         case CharGroupId::GreekBasic: CharGroup<char32_t, CharGroupId::GreekBasic>::foreach(f); break;
     405           0 :         case CharGroupId::Math: CharGroup<char32_t, CharGroupId::Math>::foreach(f); break;
     406           0 :         case CharGroupId::TextPunctuation: CharGroup<char32_t, CharGroupId::TextPunctuation>::foreach(f); break;
     407           0 :         default: break;
     408             :         }
     409           0 :         return updated;
     410             : }
     411             : 
     412      721805 : bool FontFaceObject::addRequiredChar(char32_t ch) {
     413      721805 :         std::unique_lock lock(_requiredMutex);
     414     1443610 :         return mem_std::emplace_ordered(_required, ch);
     415      721805 : }
     416             : 
     417        8820 : auto FontFaceObject::getRequiredChars() const -> Vector<char32_t> {
     418        8820 :         std::unique_lock lock(_requiredMutex);
     419       17640 :         return _required;
     420        8820 : }
     421             : 
     422     1572398 : CharShape FontFaceObject::getChar(char16_t c) const {
     423     1572398 :         std::shared_lock lock(_charsMutex);
     424     1572836 :         auto l = _chars.get(c);
     425     1572604 :         if (l && l->charID == c) {
     426     1572774 :                 return *l;
     427             :         }
     428           0 :         return CharShape{0};
     429     1572604 : }
     430             : 
     431      728488 : int16_t FontFaceObject::getKerningAmount(char16_t first, char16_t second) const {
     432      728488 :         std::shared_lock lock(_charsMutex);
     433      728488 :         uint32_t key = (first << 16) | (second & 0xffff);
     434      728488 :         auto it = _kerning.find(key);
     435      728488 :         if (it != _kerning.end()) {
     436           0 :                 return it->second;
     437             :         }
     438      728488 :         return 0;
     439      728488 : }
     440             : 
     441      507122 : bool FontFaceObject::addChar(char16_t theChar, bool &updated) {
     442             :         do {
     443             :                 // try to get char with shared lock
     444      507122 :                 std::shared_lock charsLock(_charsMutex);
     445      507122 :                 auto value = _chars.get(theChar);
     446      507122 :                 if (value) {
     447      503988 :                         if (value->charID == theChar) {
     448      405427 :                                 return true;
     449       98561 :                         } else if (value->charID == char16_t(0xFFFF)) {
     450       23564 :                                 return false;
     451             :                         }
     452             :                 }
     453      507122 :         } while (0);
     454             : 
     455       78131 :         std::unique_lock charsUniqueLock(_charsMutex);
     456       78131 :         auto value = _chars.get(theChar);
     457       78131 :         if (value) {
     458       74997 :                 if (value->charID == theChar) {
     459           0 :                         return true;
     460       74997 :                 } else if (value->charID == char16_t(0xFFFF)) {
     461           0 :                         return false;
     462             :                 }
     463             :         }
     464             : 
     465       78131 :         std::unique_lock faceLock(_faceMutex);
     466       78131 :         FT_UInt cIdx = FT_Get_Char_Index(_face, theChar);
     467       78131 :         if (!cIdx) {
     468        1742 :                 _chars.emplace(theChar, CharShape{char16_t(0xFFFF)});
     469        1742 :                 return false;
     470             :         }
     471             : 
     472             :         FT_Fixed advance;
     473       76389 :         auto err = FT_Get_Advance(_face, cIdx, FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP, &advance);
     474       76389 :         if (err != FT_Err_Ok) {
     475           0 :                 _chars.emplace(theChar, CharShape{char16_t(0xFFFF)});
     476           0 :                 return false;
     477             :         }
     478             : 
     479             :         /*auto err = FT_Load_Glyph(_face, cIdx, FT_LOAD_DEFAULT | FT_LOAD_NO_BITMAP);
     480             :         if (err != FT_Err_Ok) {
     481             :                 _chars.emplace(theChar, CharLayout{char16_t(0xFFFF)});
     482             :                 return false;
     483             :         }*/
     484             : 
     485             :         // store result in the passed rectangle
     486           0 :         _chars.emplace(theChar, CharShape{theChar,
     487             :                 //static_cast<int16_t>(_face->glyph->metrics.horiBearingX >> 6),
     488             :                 //static_cast<int16_t>(- (_face->glyph->metrics.horiBearingY >> 6)),
     489       76389 :                 static_cast<uint16_t>(advance >> 16),
     490             :                 //static_cast<uint16_t>(_face->glyph->metrics.width >> 6),
     491             :                 //static_cast<uint16_t>(_face->glyph->metrics.height >> 6)
     492             :                 });
     493             : 
     494       76389 :         if (!chars::isspace(theChar)) {
     495       75246 :                 updated = true;
     496             :         }
     497             : 
     498       76389 :         if (FT_HAS_KERNING(_face)) {
     499           0 :                 _chars.foreach([&, this] (const CharShape & it) {
     500           0 :                         if (it.charID == 0 || it.charID == char16_t(0xFFFF)) {
     501           0 :                                 return;
     502             :                         }
     503             : 
     504           0 :                         if (it.charID != theChar) {
     505             :                                 FT_Vector kerning;
     506           0 :                                 auto err = FT_Get_Kerning(_face, cIdx, cIdx, FT_KERNING_DEFAULT, &kerning);
     507           0 :                                 if (err == FT_Err_Ok) {
     508           0 :                                         auto value = int16_t(kerning.x >> 6);
     509           0 :                                         if (value != 0) {
     510           0 :                                                 _kerning.emplace(theChar << 16 | (it.charID & 0xffff), value);
     511             :                                         }
     512             :                                 }
     513             :                         } else {
     514           0 :                                 auto kIdx = FT_Get_Char_Index(_face, it.charID);
     515             : 
     516             :                                 FT_Vector kerning;
     517           0 :                                 auto err = FT_Get_Kerning(_face, cIdx, kIdx, FT_KERNING_DEFAULT, &kerning);
     518           0 :                                 if (err == FT_Err_Ok) {
     519           0 :                                         auto value = int16_t(kerning.x >> 6);
     520           0 :                                         if (value != 0) {
     521           0 :                                                 _kerning.emplace(theChar << 16 | (it.charID & 0xffff), value);
     522             :                                         }
     523             :                                 }
     524             : 
     525           0 :                                 err = FT_Get_Kerning(_face, kIdx, cIdx, FT_KERNING_DEFAULT, &kerning);
     526           0 :                                 if (err == FT_Err_Ok) {
     527           0 :                                         auto value = int16_t(kerning.x >> 6);
     528           0 :                                         if (value != 0) {
     529           0 :                                                 _kerning.emplace(it.charID << 16 | (theChar & 0xffff), value);
     530             :                                         }
     531             :                                 }
     532             :                         }
     533             :                 });
     534             :         }
     535       76389 :         return true;
     536       78131 : }
     537             : 
     538       23025 : auto FontFaceSet::constructName(StringView family, const FontSpecializationVector &vec) -> String {
     539       23025 :         return FontParameters::getFontConfigName<Interface>(family, vec.fontSize, vec.fontStyle, vec.fontWeight, vec.fontStretch, vec.fontGrade, FontVariant::Normal, false);
     540             : }
     541             : 
     542           0 : bool FontFaceSet::init(String &&name, StringView family, FontSpecializationVector &&spec, Rc<FontFaceData> &&data, FontLibrary *c) {
     543           0 :         _name = move(name);
     544           0 :         _family = family.str<Interface>();
     545           0 :         _spec = move(spec);
     546           0 :         _sources.emplace_back(move(data));
     547           0 :         _library = c;
     548           0 :         _faces.resize(_sources.size(), nullptr);
     549           0 :         if (auto face = _library->openFontFace(_sources.front(), _spec)) {
     550           0 :                 _faces[0] = face;
     551           0 :                 _metrics = _faces.front()->getMetrics();
     552           0 :         }
     553           0 :         return true;
     554             : }
     555             : 
     556        1374 : bool FontFaceSet::init(String &&name, StringView family, FontSpecializationVector &&spec, Vector<Rc<FontFaceData>> &&data, FontLibrary *c) {
     557        1374 :         _name = move(name);
     558        1374 :         _family = family.str<Interface>();
     559        1374 :         _spec = move(spec);
     560        1374 :         _sources = move(data);
     561        1374 :         _faces.resize(_sources.size(), nullptr);
     562        1374 :         _library = c;
     563        1374 :         if (auto face = _library->openFontFace(_sources.front(), _spec)) {
     564        1374 :                 _faces[0] = face;
     565        1374 :                 _metrics = _faces.front()->getMetrics();
     566        1374 :         }
     567        1374 :         return true;
     568             : }
     569             : 
     570       20163 : void FontFaceSet::touch(uint64_t clock, bool persistent) {
     571       20163 :         _accessTime = clock;
     572       20163 :         _persistent = persistent;
     573       20163 : }
     574             : 
     575       17713 : bool FontFaceSet::addString(const CharVector &str) {
     576       17713 :         Vector<char32_t> failed;
     577       35426 :         return addString(str, failed);
     578       17713 : }
     579             : 
     580       17713 : bool FontFaceSet::addString(const CharVector &str, Vector<char32_t> &failed) {
     581       17713 :         std::shared_lock sharedLock(_mutex);
     582             : 
     583       17713 :         bool shouldOpenFonts = false;
     584       17713 :         bool updated = false;
     585       17713 :         size_t i = 0;
     586             : 
     587       42148 :         for (auto &it : _faces) {
     588       30366 :                 if (i == 0) {
     589       17713 :                         if (it->addChars(str.chars, i == 0, &failed)) {
     590        2414 :                                 updated = true;
     591             :                         }
     592             :                 } else {
     593       12653 :                         if (it == nullptr) {
     594         871 :                                 shouldOpenFonts = true;
     595         871 :                                 break;
     596             :                         }
     597             : 
     598       11782 :                         auto tmp = move(failed);
     599       11782 :                         failed.clear();
     600             : 
     601       11782 :                         if (it->addChars(tmp, i == 0, &failed)) {
     602           0 :                                 updated = true;
     603             :                         }
     604       11782 :                 }
     605             : 
     606       29495 :                 if (failed.empty()) {
     607        5060 :                         break;
     608             :                 }
     609             : 
     610       24435 :                 ++ i;
     611             :         }
     612             : 
     613       17713 :         if (shouldOpenFonts) {
     614         871 :                 sharedLock.unlock();
     615         871 :                 std::unique_lock lock(_mutex);
     616             : 
     617        1742 :                 for (; i < _faces.size(); ++ i) {
     618         871 :                         if (_faces[i] == nullptr) {
     619         871 :                                 _faces[i] = _library->openFontFace(_sources[i], _spec);
     620             :                         }
     621             : 
     622         871 :                         auto tmp = move(failed);
     623         871 :                         failed.clear();
     624             : 
     625         871 :                         if (_faces[i]->addChars(tmp, i == 0, &failed)) {
     626           0 :                                 updated = true;
     627             :                         }
     628             : 
     629         871 :                         if (failed.empty()) {
     630           0 :                                 break;
     631             :                         }
     632         871 :                 }
     633         871 :         }
     634             : 
     635       17713 :         return updated;
     636       17713 : }
     637             : 
     638       74112 : uint16_t FontFaceSet::getFontHeight() const {
     639       74112 :         return _metrics.height;
     640             : }
     641             : 
     642      745946 : int16_t FontFaceSet::getKerningAmount(char16_t first, char16_t second, uint16_t face) const {
     643      745946 :         std::shared_lock lock(_mutex);
     644      777240 :         for (auto &it : _faces) {
     645      763404 :                 if (it) {
     646      759782 :                         if (it->getId() == face) {
     647      732110 :                                 return it->getKerningAmount(first, second);
     648             :                         }
     649             :                 } else {
     650        3622 :                         return 0;
     651             :                 }
     652             :         }
     653       13836 :         return 0;
     654      745946 : }
     655             : 
     656       33634 : Metrics FontFaceSet::getMetrics() const {
     657       33634 :         return _metrics;
     658             : }
     659             : 
     660     1572160 : CharShape FontFaceSet::getChar(char16_t ch, uint16_t &face) const {
     661     1572160 :         std::shared_lock lock(_mutex);
     662     1572798 :         for (auto &it : _faces) {
     663     1572615 :                 auto l = it->getChar(ch);
     664     1572547 :                 if (l.charID != 0) {
     665     1572547 :                         face = it->getId();
     666     1572595 :                         return l;
     667             :                 }
     668             :         }
     669           0 :         return CharShape();
     670     1572595 : }
     671             : 
     672       15886 : bool FontFaceSet::addTextureChars(SpanView<CharLayoutData> chars) const {
     673       15886 :         std::shared_lock lock(_mutex);
     674             : 
     675       15886 :         bool ret = false;
     676      878373 :         for (auto &it : chars) {
     677      862487 :                 if (chars::isspace(it.charID) || it.charID == char16_t(0x0A) || it.charID == char16_t(0x00AD)) {
     678      140682 :                         continue;
     679             :                 }
     680             : 
     681     2021961 :                 for (auto &f : _faces) {
     682     1371883 :                         if (f && f->getId() == it.face) {
     683      721805 :                                 if (f->addRequiredChar(it.charID)) {
     684       71727 :                                         ++ _texturesCount;
     685       71727 :                                         ret = true;
     686       71727 :                                         break;
     687             :                                 }
     688             :                         }
     689             :                 }
     690             :         }
     691       15886 :         return ret;
     692       15886 : }
     693             : 
     694        5539 : auto FontFaceSet::getFaces() const -> const Vector<Rc<FontFaceObject>> & {
     695        5539 :         return _faces;
     696             : }
     697             : 
     698           0 : size_t FontFaceSet::getFaceCount() const {
     699           0 :         return _sources.size();
     700             : }
     701             : 
     702           0 : Rc<FontFaceData> FontFaceSet::getSource(size_t idx) const {
     703           0 :         if (idx < _sources.size()) {
     704           0 :                 return _sources[idx];
     705             :         }
     706           0 :         return nullptr;
     707             : }
     708             : 
     709             : }

Generated by: LCOV version 1.14