LCOV - code coverage report
Current view: top level - core/font - SPFontLibrary.cc (source / functions) Hit Total Coverage
Test: coverage.info Lines: 144 195 73.8 %
Date: 2024-05-12 00:16:13 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /**
       2             :  Copyright (c) 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 "SPFontLibrary.h"
      24             : 
      25             : #include "ft2build.h"
      26             : #include FT_FREETYPE_H
      27             : #include FT_GLYPH_H
      28             : #include FT_MULTIPLE_MASTERS_H
      29             : #include FT_SFNT_NAMES_H
      30             : #include FT_ADVANCES_H
      31             : 
      32             : #include "SPFontFace.h"
      33             : 
      34             : namespace STAPPLER_VERSIONIZED stappler::font {
      35             : 
      36             : #include "SPFont-RobotoMono-Italic-VariableFont_wght.ttf.cc"
      37             : #include "SPFont-RobotoMono-VariableFont_wght.ttf.cc"
      38             : #include "SPFont-RobotoFlex-VariableFont.ttf.cc"
      39             : #include "SPFont-DejaVuSansStappler.cc"
      40             : 
      41        8942 : FontFaceObjectHandle::~FontFaceObjectHandle() {
      42        4471 :         if (_onDestroy) {
      43        4471 :                 _onDestroy(this);
      44        4471 :                 _onDestroy = nullptr;
      45             :         }
      46        4471 :         _library = nullptr;
      47        4471 :         _face = nullptr;
      48        8942 : }
      49             : 
      50        4471 : bool FontFaceObjectHandle::init(const Rc<FontLibrary> &lib, Rc<FontFaceObject> &&obj, Function<void(const FontFaceObjectHandle *)> &&onDestroy) {
      51        4471 :         _face = move(obj);
      52        4471 :         _library = lib;
      53        4471 :         _onDestroy = move(onDestroy);
      54        4471 :         return true;
      55             : }
      56             : 
      57      149577 : bool FontFaceObjectHandle::acquireTexture(char16_t theChar, const Callback<void(const CharTexture &)> &cb) {
      58      149577 :         return _face->acquireTextureUnsafe(theChar, cb);
      59             : }
      60             : 
      61         198 : BytesView FontLibrary::getFont(DefaultFontName name) {
      62         198 :         switch (name) {
      63           0 :         case DefaultFontName::None: return BytesView(); break;
      64          50 :         case DefaultFontName::RobotoFlex_VariableFont:
      65          50 :                 return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoFlex_VariableFont), sizeof(s_font_RobotoFlex_VariableFont));
      66             :                 break;
      67          50 :         case DefaultFontName::RobotoMono_VariableFont:
      68          50 :                 return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoMono_VariableFont), sizeof(s_font_RobotoMono_VariableFont));
      69             :                 break;
      70          50 :         case DefaultFontName::RobotoMono_Italic_VariableFont:
      71          50 :                 return BytesView(reinterpret_cast<const uint8_t *>(s_font_RobotoMono_Italic_VariableFont), sizeof(s_font_RobotoMono_Italic_VariableFont));
      72             :                 break;
      73          50 :         case DefaultFontName::DejaVuSans:
      74          50 :                 return BytesView(reinterpret_cast<const uint8_t *>(s_font_DejaVuSansStappler), sizeof(s_font_DejaVuSansStappler));
      75             :                 break;
      76             :         }
      77           0 :         return BytesView();
      78             : }
      79             : 
      80         200 : StringView FontLibrary::getFontName(DefaultFontName name) {
      81         200 :         switch (name) {
      82           0 :         case DefaultFontName::None: return StringView(); break;
      83          50 :         case DefaultFontName::RobotoFlex_VariableFont: return StringView("RobotoFlex_VariableFont"); break;
      84          50 :         case DefaultFontName::RobotoMono_VariableFont: return StringView("RobotoMono_VariableFont"); break;
      85          50 :         case DefaultFontName::RobotoMono_Italic_VariableFont: return StringView("RobotoMono_Italic_VariableFont"); break;
      86          50 :         case DefaultFontName::DejaVuSans: return StringView("DejaVuSans"); break;
      87             :         }
      88           0 :         return StringView();
      89             : }
      90             : 
      91          50 : FontLibrary::FontLibrary() {
      92          50 :         FT_Init_FreeType( &_library );
      93          50 : }
      94             : 
      95         100 : FontLibrary::~FontLibrary() {
      96          50 :         if (_library) {
      97          50 :                 FT_Done_FreeType(_library);
      98          50 :                 _library = nullptr;
      99             :         }
     100         100 : }
     101             : 
     102         192 : Rc<FontFaceData> FontLibrary::openFontData(StringView dataName, FontLayoutParameters params,
     103             :                 bool isParamsPreconfigured, const Callback<FontData()> &dataCallback) {
     104         192 :         std::unique_lock lock(_mutex);
     105             : 
     106         200 :         auto it = _data.find(dataName);
     107         200 :         if (it != _data.end()) {
     108           0 :                 return it->second;
     109             :         }
     110             : 
     111         200 :         if (!dataCallback) {
     112           0 :                 return nullptr;
     113             :         }
     114             : 
     115         200 :         lock.unlock();
     116         200 :         auto fontData = dataCallback();
     117         195 :         if (fontData.view.empty() && !fontData.callback) {
     118           0 :                 return nullptr;
     119             :         }
     120             : 
     121         194 :         Rc<FontFaceData> dataObject;
     122         193 :         if (fontData.callback) {
     123         148 :                 dataObject = Rc<FontFaceData>::create(dataName, move(fontData.callback));
     124          50 :         } else if (fontData.persistent) {
     125          50 :                 dataObject = Rc<FontFaceData>::create(dataName, move(fontData.view), true);
     126             :         } else {
     127           0 :                 dataObject = Rc<FontFaceData>::create(dataName, move(fontData.bytes));
     128             :         }
     129         200 :         if (dataObject) {
     130         200 :                 lock.lock();
     131         200 :                 _data.emplace(dataObject->getName(), dataObject);
     132             : 
     133         200 :                 auto face = newFontFace(dataObject->getView());
     134         200 :                 lock.unlock();
     135         200 :                 if (!isParamsPreconfigured) {
     136          50 :                         params = dataObject->acquireDefaultParams(face);
     137             :                 }
     138         200 :                 dataObject->inspectVariableFont(params, _library, face);
     139         200 :                 lock.lock();
     140         200 :                 doneFontFace(face);
     141             :         }
     142         200 :         return dataObject;
     143         200 : }
     144             : 
     145           0 : Rc<FontFaceObject> FontLibrary::openFontFace(StringView dataName, const FontSpecializationVector &spec, const Callback<FontData()> &dataCallback) {
     146           0 :         String faceName = mem_std::toString(dataName, spec.getSpecializationArgs<Interface>());
     147             : 
     148           0 :         std::unique_lock lock(_mutex);
     149             :         do {
     150           0 :                 auto it = _faces.find(faceName);
     151           0 :                 if (it != _faces.end()) {
     152           0 :                         return it->second;
     153             :                 }
     154             :         } while (0);
     155             : 
     156           0 :         auto it = _data.find(dataName);
     157           0 :         if (it != _data.end()) {
     158           0 :                 auto face = newFontFace(it->second->getView());
     159           0 :                 auto ret = Rc<FontFaceObject>::create(faceName, it->second, _library, face, spec, getNextId());
     160           0 :                 if (ret) {
     161           0 :                         _faces.emplace(ret->getName(), ret);
     162             :                 } else {
     163           0 :                         doneFontFace(face);
     164             :                 }
     165           0 :                 return ret;
     166           0 :         }
     167             : 
     168           0 :         if (!dataCallback) {
     169           0 :                 return nullptr;
     170             :         }
     171             : 
     172           0 :         auto fontData = dataCallback();
     173           0 :         if (fontData.view.empty()) {
     174           0 :                 return nullptr;
     175             :         }
     176             : 
     177           0 :         Rc<FontFaceData> dataObject;
     178           0 :         if (fontData.persistent) {
     179           0 :                 dataObject = Rc<FontFaceData>::create(dataName, move(fontData.view), true);
     180             :         } else {
     181           0 :                 dataObject = Rc<FontFaceData>::create(dataName, move(fontData.bytes));
     182             :         }
     183             : 
     184           0 :         if (dataObject) {
     185           0 :                 _data.emplace(dataObject->getName(), dataObject);
     186           0 :                 auto face = newFontFace(dataObject->getView());
     187           0 :                 auto ret = Rc<FontFaceObject>::create(faceName, it->second, _library, face, spec, getNextId());
     188           0 :                 if (ret) {
     189           0 :                         _faces.emplace(ret->getName(), ret);
     190             :                 } else {
     191           0 :                         doneFontFace(face);
     192             :                 }
     193           0 :                 return ret;
     194           0 :         }
     195             : 
     196           0 :         return nullptr;
     197           0 : }
     198             : 
     199        2245 : Rc<FontFaceObject> FontLibrary::openFontFace(const Rc<FontFaceData> &dataObject, const FontSpecializationVector &spec) {
     200        2245 :         String faceName = mem_std::toString(dataObject->getName(), spec.getSpecializationArgs<Interface>());
     201             : 
     202        2245 :         std::unique_lock lock(_mutex);
     203             :         do {
     204        2245 :                 auto it = _faces.find(faceName);
     205        2245 :                 if (it != _faces.end()) {
     206           0 :                         return it->second;
     207             :                 }
     208             :         } while (0);
     209             : 
     210        2245 :         auto face = newFontFace(dataObject->getView());
     211        2245 :         auto ret = Rc<FontFaceObject>::create(faceName, dataObject, _library, face, spec, getNextId());
     212        2245 :         if (ret) {
     213        2245 :                 _faces.emplace(ret->getName(), ret);
     214             :         } else {
     215           0 :                 doneFontFace(face);
     216             :         }
     217        2245 :         return ret;
     218        2245 : }
     219             : 
     220          50 : void FontLibrary::invalidate() {
     221          50 :         std::unique_lock uniqueLock(_sharedMutex);
     222             : 
     223          50 :         _threads.clear();
     224          50 :         _faces.clear();
     225          50 :         _data.clear();
     226          50 : }
     227             : 
     228        4815 : void FontLibrary::update() {
     229        4815 :         Vector<Rc<FontFaceObject>> erased;
     230        4815 :         std::unique_lock lock(_mutex);
     231             : 
     232             :         do {
     233        4815 :                 auto it = _faces.begin();
     234       41969 :                 while (it != _faces.end()) {
     235       37154 :                         if (it->second->getReferenceCount() == 1) {
     236        1966 :                                 releaseId(it->second->getId());
     237        1966 :                                 doneFontFace(it->second->getFace());
     238        1966 :                                 erased.emplace_back(it->second.get());
     239        1966 :                                 it = _faces.erase(it);
     240             :                         } else {
     241       35188 :                                 ++ it;
     242             :                         }
     243             :                 }
     244             :         } while (0);
     245             : 
     246             :         do {
     247        4815 :                 auto it = _data.begin();
     248       24002 :                 while (it != _data.end()) {
     249       19187 :                         if (it->second->getReferenceCount() == 1) {
     250           0 :                                 it = _data.erase(it);
     251             :                         } else {
     252       19187 :                                 ++ it;
     253             :                         }
     254             :                 }
     255             :         } while (0);
     256             : 
     257        4815 :         lock.unlock();
     258             : 
     259        4815 :         std::unique_lock uniqueLock(_sharedMutex);
     260        6781 :         for (auto &it : erased) {
     261        1966 :                 _threads.erase(it.get());
     262             :         }
     263        4815 : }
     264             : 
     265        2245 : uint16_t FontLibrary::getNextId() {
     266       13557 :         for (uint32_t i = 1; i < _fontIds.size(); ++ i) {
     267       13557 :                 if (!_fontIds.test(i)) {
     268        2245 :                         _fontIds.set(i);
     269        2245 :                         return i;
     270             :                 }
     271             :         }
     272           0 :         abort(); // active font limits exceeded
     273             :         return 0;
     274             : }
     275             : 
     276        1966 : void FontLibrary::releaseId(uint16_t id) {
     277        1966 :         _fontIds.reset(id);
     278        1966 : }
     279             : 
     280       15716 : Rc<FontFaceObjectHandle> FontLibrary::makeThreadHandle(const Rc<FontFaceObject> &obj) {
     281       15716 :         std::shared_lock sharedLock(_sharedMutex);
     282       15677 :         auto it = _threads.find(obj.get());
     283       15367 :         if (it != _threads.end()) {
     284       14065 :                 auto iit = it->second.find(std::this_thread::get_id());
     285       14180 :                 if (iit != it->second.end()) {
     286       11184 :                         return iit->second;
     287             :                 }
     288             :         }
     289        4251 :         sharedLock.unlock();
     290             : 
     291        4399 :         std::unique_lock uniqueLock(_sharedMutex);
     292        4471 :         it = _threads.find(obj.get());
     293        4471 :         if (it != _threads.end()) {
     294        3349 :                 auto iit = it->second.find(std::this_thread::get_id());
     295        3349 :                 if (iit != it->second.end()) {
     296           0 :                         return iit->second;
     297             :                 }
     298             :         }
     299             : 
     300        4471 :         std::unique_lock lock(_mutex);
     301        4471 :         auto face = newFontFace(obj->getData()->getView());
     302        4471 :         lock.unlock();
     303        4471 :         auto target = Rc<FontFaceObject>::create(obj->getName(), obj->getData(), _library, face, obj->getSpec(), obj->getId());
     304             : 
     305        4471 :         if (it == _threads.end()) {
     306        1122 :                 it = _threads.emplace(obj.get(), Map<std::thread::id, Rc<FontFaceObjectHandle>>()).first;
     307             :         }
     308             : 
     309        8942 :         auto iit = it->second.emplace(std::this_thread::get_id(), Rc<FontFaceObjectHandle>::create(this, move(target), [this] (const FontFaceObjectHandle *obj) {
     310        4471 :                 std::unique_lock lock(_mutex);
     311        4471 :                 doneFontFace(obj->getFace());
     312        8942 :         })).first->second;
     313        4471 :         uniqueLock.unlock();
     314        4471 :         return iit;
     315       15648 : }
     316             : 
     317        6916 : FT_Face FontLibrary::newFontFace(BytesView data) {
     318        6916 :         FT_Face ret = nullptr;
     319        6916 :         FT_Error err = FT_Err_Ok;
     320             : 
     321        6916 :         err = FT_New_Memory_Face(_library, data.data(), data.size(), 0, &ret );
     322        6916 :         if (err != FT_Err_Ok) {
     323           0 :                 auto str = FT_Error_String(err);
     324           0 :                 log::error("font::FontLibrary", str ? StringView(str) : "Unknown error");
     325           0 :                 return nullptr;
     326             :         }
     327             : 
     328        6916 :         return ret;
     329             : }
     330             : 
     331        6637 : void FontLibrary::doneFontFace(FT_Face face) {
     332        6637 :         if (face) {
     333        6637 :                 FT_Done_Face(face);
     334             :         }
     335        6637 : }
     336             : 
     337             : }

Generated by: LCOV version 1.14