LCOV - code coverage report
Current view: top level - src/rendering/fonts - read_fonts.cc (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 137 141 97.2 %
Date: 2022-06-15 20:16:21 Functions: 15 15 100.0 %
Branches: 170 282 60.3 %

           Branch data     Line data    Source code
       1                 :            : /** @file rendering/fonts/read_fonts.cc
       2                 :            :  * @brief Loads the list of available fonts and the list of characters in each. Used by FontPlan.
       3                 :            :  */
       4                 :            : #include <cstdio>
       5                 :            : 
       6                 :            : #include <future>
       7                 :            : #include <charconv>
       8                 :            : #include <fstream>
       9                 :            : #include <sstream>
      10                 :            : #include <regex>
      11                 :            : 
      12                 :            : #include "read_fonts.hh"
      13                 :            : #include "read_font.hh"
      14                 :            : #include "endian.hh"
      15                 :            : #include "share.hh"
      16                 :            : 
      17                 :            : using namespace std::literals;
      18                 :            : 
      19                 :            : static constexpr auto Ropt = std::regex_constants::ECMAScript | std::regex_constants::optimize;
      20                 :            : 
      21                 :        189 : static std::string GuessEncoding(std::string_view name)
      22                 :            : {
      23                 :        189 :     static const unsigned char latin[] = {0, 1, 2, 3, 4, 9, 10, 13, 14, 15, 16 };
      24                 :        189 :     unsigned iso = 0;
      25   [ +  -  +  + ]:        189 :     if(name.size() >= 4 && name.compare(name.size()-4,4, ".inc"sv) == 0)
      26                 :            :     {
      27         [ +  + ]:          3 :         if(name == "8x12.inc"sv) return "ibm-cp850";
      28                 :          2 :         return "ibm-cp437";
      29                 :            :     }
      30         [ +  + ]:        186 :     if(name == "4x5.bdf"sv)
      31                 :          1 :         return "xorg-4x5";
      32         [ +  + ]:        185 :     if(name.compare(0,3, "lat"sv) == 0)
      33                 :            :     {
      34                 :         21 :         unsigned value = 0;
      35                 :         21 :         std::from_chars(name.data()+3, name.data()+name.size(), value);
      36         [ +  - ]:         21 :         if(value > 0 && value < std::size(latin)) iso = latin[value];
      37                 :            :     }
      38         [ +  + ]:        164 :     else if(name.compare(0,3, "iso"sv) == 0)
      39                 :            :     {
      40                 :         18 :         std::from_chars(name.data()+3, name.data()+name.size(), iso);
      41                 :            :     }
      42         [ +  + ]:        185 :     if(iso)
      43         [ +  - ]:         78 :         return "iso-8859-" + std::to_string(iso);
      44                 :        189 :     return {};
      45                 :            : }
      46                 :            : 
      47                 :          2 : static auto FontPath()
      48                 :            : {
      49   [ +  -  +  -  :          8 :     return FindShareFile(std::filesystem::path("fonts") / std::filesystem::path("files"));
                   +  - ]
      50                 :            : }
      51                 :            : 
      52                 :          1 : void ReadFonts(std::ostream& out)
      53                 :            : {
      54         [ +  - ]:          1 :     std::vector<std::future<std::string>> tasks;
      55                 :            : 
      56         [ +  - ]:          1 :     auto [fn, status] = FontPath();
      57   [ +  -  +  -  :        104 :     for(auto p: std::filesystem::directory_iterator(fn))
          +  -  +  -  +  
             -  +  +  -  
                      + ]
      58   [ +  -  +  - ]:        100 :         if(!p.is_directory())
      59                 :            :         {
      60   [ +  -  +  - ]:        300 :             std::string guess_enc = GuessEncoding(std::string(p.path().filename()));
      61         [ +  - ]:        100 :             std::fprintf(stderr, "Reading %s ...\n", p.path().c_str());
      62                 :            : 
      63   [ +  -  +  -  :        200 :             tasks.emplace_back(std::async(std::launch::async, [=]
             +  -  +  - ]
      64                 :            :             {
      65         [ +  - ]:        100 :                 auto data = Read_Font(p.path(), 0,0, false, guess_enc);
      66                 :            : 
      67         [ +  - ]:        100 :                 std::ostringstream temp;
      68   [ +  -  +  -  :        100 :                 temp << "FONT "sv << p.path().filename() << '\n';
             +  -  +  - ]
      69   [ +  -  +  + ]:        200 :                 for(auto w: std::vector<unsigned>(data.widths)) // make copy
      70                 :            :                 {
      71   [ +  -  +  -  :        100 :                     temp << "SIZE "sv << w << ' ' << data.height << '\n';
          +  -  +  -  +  
                      - ]
      72         [ +  + ]:        100 :                     if(!data.unicode)
      73                 :            :                     {
      74   [ +  -  +  -  :         11 :                         temp << "GUESSED_ENCODING \""sv << guess_enc << "\"\n"sv;
                   +  - ]
      75                 :            :                     }
      76                 :            : 
      77   [ +  -  +  - ]:        100 :                     data = Read_Font(p.path(), w, data.height, false, guess_enc);
      78                 :            : 
      79         [ +  - ]:        100 :                     std::vector<bool> bitmap(65536);
      80         [ +  + ]:     286553 :                     for(auto [ch, ofs]: data.glyphs)
      81                 :            :                     {
      82   [ +  -  -  + ]:     286453 :                         while(bitmap.size() <= ch) bitmap.resize(bitmap.size() + 65536);
      83                 :     287491 :                         bitmap[ch] = true;
      84                 :            :                     }
      85                 :            : 
      86                 :       5941 :                     auto PrintRange = [&](char32_t begin, char32_t length)
      87                 :            :                     {
      88         [ +  + ]:       5841 :                         if(length == 1)
      89                 :            :                         {
      90                 :       1770 :                             char buf[64] = "  CHAR ";
      91                 :       1770 :                             auto [p, erc]  = std::to_chars(buf+7, buf+sizeof(buf)-1, begin, 16);
      92                 :       1770 :                             *p++ = '\n';
      93                 :       1770 :                             temp << std::string_view(buf, p-buf);
      94                 :            :                         }
      95                 :            :                         else
      96                 :            :                         {
      97                 :       4071 :                             char buf[80] = "  CHARS ";
      98                 :       4071 :                             auto [p, erc]   = std::to_chars(buf+8, buf+sizeof(buf)/2,  begin,          16);
      99                 :       4071 :                             p[0] = ' '; p[1] = '-'; p[2] = ' ';
     100                 :       4071 :                             auto [p2, erc2] = std::to_chars(p+3,   buf+sizeof(buf)-1,  begin+length-1, 16);
     101                 :       4071 :                             *p2++ = '\n';
     102                 :       4071 :                             temp << std::string_view(buf, p2-buf);
     103                 :            :                         }
     104                 :       5941 :                     };
     105                 :            : 
     106                 :            :                     /* Express the coverage bitmap in a compact form. */
     107         [ +  + ]:    3214964 :                     for(std::size_t begin=0; begin<bitmap.size(); ++begin)
     108                 :            :                     {
     109         [ +  + ]:    3214864 :                         if(!bitmap[begin]) continue;
     110                 :            :                         std::size_t length = 1;
     111   [ +  -  +  + ]:     195612 :                         while(begin+length < bitmap.size() && bitmap[begin+length]) ++length;
     112                 :            :                     #if 1
     113                 :     659315 :                         std::uint_fast64_t bits=0, run=1, popcount=0, toggles=0, wbits = 64;
     114         [ +  + ]:     659315 :                         for(std::size_t bit=0; bit<64; ++bit)
     115   [ +  +  +  + ]:     649120 :                             if(begin+bit < bitmap.size() && bitmap[begin+bit])
     116         [ +  + ]:     362832 :                                 { if(!run) {++toggles;} bits |= 1ull << bit; ++run; ++popcount; }
     117                 :            :                             else
     118         [ +  + ]:     286290 :                                 { if(run)  {++toggles;} run = 0; }
     119         [ +  + ]:      10195 :                         if(run >= 8)
     120                 :            :                         {
     121                 :       1898 :                             bits = (bits << run) >> run;
     122                 :       1898 :                             wbits -= run;
     123                 :            :                         }
     124                 :            : 
     125         [ +  + ]:      10195 :                         if(toggles >= 3 && !run)
     126                 :            :                         {
     127                 :       4354 :                             char buf[128] = "  MAP ";
     128                 :            :                             /* Put first character index in hex */
     129                 :       4354 :                             auto [p, erc]   = std::to_chars(buf+6, buf+sizeof(buf)/2, begin, 16);
     130                 :       4354 :                             p[0] = ' ';
     131                 :            :                             /* Put coverage bitmap (64-bit integer) in binary */
     132                 :       4354 :                             auto [p2, erc2] = std::to_chars(p+1,   buf+sizeof(buf)-1, bits,   2);
     133                 :       4354 :                             *p2++ = '\n';
     134         [ +  - ]:       4354 :                             temp << std::string_view(buf, p2-buf);
     135                 :       4354 :                             begin += wbits-1;
     136                 :            :                         }
     137                 :            :                         else
     138                 :            :                     #endif
     139                 :            :                         {
     140         [ +  - ]:       5841 :                             PrintRange(begin, length);
     141                 :       5841 :                             begin += length-1;
     142                 :            :                         }
     143                 :            :                     }
     144                 :        100 :                 }
     145                 :            : 
     146         [ +  - ]:        100 :                 std::fprintf(stderr, ".");
     147                 :            : 
     148         [ +  - ]:        100 :                 temp << '\n';
     149         [ +  - ]:        200 :                 return temp.str();
     150                 :        100 :             }));
     151   [ +  -  -  +  :        201 :         }
             +  -  -  - ]
     152   [ +  -  +  + ]:        101 :     for(auto& t: tasks) out << t.get();
     153         [ +  - ]:          1 :     std::fprintf(stderr, "Fonts loaded.");
     154                 :          1 : }
     155                 :            : 
     156                 :            : #pragma GCC push_options
     157                 :            : #pragma GCC optimize ("Ofast")
     158                 :            : template<unsigned l>
     159                 :      54581 : static bool rmatch(std::string_view str, std::smatch& mat, const std::string& line)
     160                 :            : {
     161   [ +  +  +  -  :      54581 :     static std::regex r(std::string(str), Ropt);
             +  -  +  - ]
     162                 :      54581 :     return std::regex_match(line, mat, r);
     163                 :            : }
     164                 :            : #pragma GCC pop_options
     165                 :            : 
     166                 :          1 : FontsInfo ParseFontsList(std::istream& f)
     167                 :            : {
     168                 :          1 :     FontsInfo result;
     169                 :            : 
     170                 :            :     #define r(str) rmatch<__LINE__>(str##sv, mat, line)
     171                 :            : 
     172                 :          1 :     std::string filename;
     173                 :          1 :     unsigned    x=0, y=0;
     174                 :          1 :     std::smatch mat;
     175                 :            : 
     176                 :          1 :     std::vector<bool> bitmap;
     177                 :          1 :     std::string guessed_encoding;
     178                 :        202 :     auto Flush = [&]()
     179                 :            :     {
     180         [ +  + ]:        201 :         if(!bitmap.empty())
     181                 :            :         {
     182   [ +  +  +  - ]:        200 :             if(guessed_encoding.empty()) { guessed_encoding = GuessEncoding(filename); }
     183   [ +  -  +  - ]:        100 :             result[ std::pair(filename, std::pair(x,y)) ] = std::pair(std::move(guessed_encoding), std::move(bitmap));
     184                 :        100 :             bitmap.clear();
     185                 :            :         }
     186                 :        201 :     };
     187                 :     287596 :     auto Set = [&](std::size_t n)
     188                 :            :     {
     189   [ +  +  +  + ]:     290813 :         while(bitmap.size() <= n) bitmap.resize(bitmap.size() + (n-bitmap.size() < 16384 ? 512 : 32768));
     190                 :     287595 :         bitmap[n] = true;
     191                 :     287596 :     };
     192                 :            : 
     193   [ +  -  +  + ]:      10507 :     for(std::string line; std::getline(f,line), f; )
     194                 :            :     {
     195   [ +  -  +  + ]:      10506 :         if(r("FONT[ \t]+\"([^\"]+)\""))
     196                 :            :         {
     197         [ +  - ]:        100 :             Flush();
     198         [ +  - ]:        100 :             filename = mat[1];
     199                 :            :         }
     200   [ +  -  +  + ]:      10406 :         else if(r("GUESSED_ENCODING[ \t]+\"([^\"]+)\""))
     201                 :            :         {
     202         [ +  - ]:         11 :             guessed_encoding = mat[1];
     203                 :            :         }
     204   [ +  -  +  + ]:      10395 :         else if(r("[ \t]*SIZE[ \t]+([0-9]+)[ \t]+([0-9]+)"))
     205                 :            :         {
     206         [ +  - ]:        100 :             Flush();
     207   [ +  -  +  - ]:        100 :             x = std::stoi(mat[1]);
     208   [ +  -  +  - ]:        100 :             y = std::stoi(mat[2]);
     209                 :            :         }
     210   [ +  -  +  + ]:      10295 :         else if(r("[ \t]*CHAR[ \t]+([0-9a-fA-F]+)"))
     211                 :            :         {
     212   [ +  -  +  - ]:       1770 :             unsigned a = std::stoi(mat[1], nullptr, 16);
     213         [ +  - ]:       1770 :             Set(a);
     214                 :            :         }
     215   [ +  -  +  + ]:       8525 :         else if(r("[ \t]*CHARS[ \t]+([0-9a-fA-F]+)[ \t]*-[ \t]*([0-9a-fA-F]+)"))
     216                 :            :         {
     217   [ +  -  +  -  :       4071 :             unsigned a = std::stoi(mat[1], nullptr, 16), b = std::stoi(mat[2], nullptr, 16);
             +  -  +  - ]
     218   [ +  -  +  + ]:     182471 :             while(a <= b) Set(a++);
     219                 :            :         }
     220   [ +  -  +  + ]:       4454 :         else if(r("[ \t]*MAP[ \t]+([0-9a-fA-F]+)[ \t]+([01]+)"))
     221                 :            :         {
     222   [ +  -  +  - ]:       4354 :             unsigned a = std::stoi(mat[1], nullptr, 16);
     223         [ +  + ]:     241343 :             for(long n=0; n<mat[2].length(); ++n)
     224         [ +  + ]:     236989 :                 if(mat[2].first[n] == '1')
     225         [ +  - ]:     107425 :                     Set(a + mat[2].length() - (n+1));
     226                 :            :         }
     227                 :          0 :     }
     228                 :            : 
     229                 :            :     #undef r
     230         [ +  - ]:          1 :     Flush();
     231                 :          1 :     return result;
     232                 :          1 : }
     233                 :            : 
     234                 :          1 : FontsInfo ReadFontsList()
     235                 :            : {
     236   [ +  -  +  - ]:          2 :     auto [path, status] = FindCacheFile("fonts-list.dat", true);
     237         [ +  - ]:          1 :     auto [fn, status2] = FontPath();
     238         [ -  + ]:          2 :     if(!std::filesystem::exists(status)
     239   [ #  #  #  # ]:          0 :     || !std::filesystem::file_size(path)
     240   [ #  #  #  # ]:          0 :     || (std::filesystem::exists(fn)
     241   [ #  #  #  #  :          0 :      && std::filesystem::last_write_time(fn) > std::filesystem::last_write_time(path)))
                   #  # ]
     242                 :            :     {
     243         [ +  - ]:          1 :         std::fprintf(stderr, "Building fonts cache...\n");
     244         [ +  - ]:          1 :         std::ofstream file(path);
     245         [ +  - ]:          1 :         ReadFonts(file);
     246                 :          1 :     }
     247         [ +  - ]:          1 :     std::ifstream f(path);
     248         [ +  - ]:          1 :     return ParseFontsList(f);
     249                 :          3 : }

Generated by: LCOV version 1.16