327 lines · 10.0 KB · C++
RawDownload
/* This file is part of Zutty. * Copyright (C) 2020 Tom Szilagyi * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * See the file LICENSE for the full license. */ #include "fontpack.h"#include "log.h" #include <ftw.h>//#include <stdio.h> // DEBUG#include <string.h>#include <strings.h> namespace{   struct SearchState   {      // input      const char* fontname = nullptr;      size_t fontnamelen = 0;       // output      int level = 0;      std::string ext;      std::string regular;      std::string bold;      std::string italic;      std::string boldItalic;   };   SearchState sstate;    int   saveCandidate (const char* fpath, const char* ext, int level,                  const char* variant, std::string& dest)   {      logT << variant << ": " << fpath << std::endl;      if (sstate.ext != "" && sstate.ext != ext)      {         logT << "Rejecting candidate because its extension: '" << ext              << "' does not match the other(s): '" << sstate.ext << "'"              << std::endl;         return 1;      }      dest = fpath;      sstate.ext = ext;      sstate.level = level;      return 0;   }    int   fontFileFilter (const char* fpath, const struct stat* sb,                   int tflag, struct FTW* ftwbuf)   {      // If we have just emerged from a directory where fonts were found,      // time to call it a day.      if (tflag == FTW_D &&          sstate.level > 0 && ftwbuf->level == sstate.level - 1 &&          sstate.regular.size () > 0)         return 1;       // In a less ideal case, where some candidates were found in this dir,      // but no regular variant, clear partial results and proceed.      if (tflag == FTW_D && sstate.level > 0)      {         logT << "Some candidates found but no regular variant; continuing"              << std::endl;         sstate.level = 0;         sstate.ext = "";         sstate.regular = "";         sstate.bold = "";         sstate.italic = "";         sstate.boldItalic = "";         return 0;      }       // Filter by file type - only regular files and symlinks      if (tflag != FTW_F && tflag != FTW_SL)         return 0;       // Filter by extension      const char* fname = fpath + ftwbuf->base;      const char* ext = strrchr (fname, '.');      if (!ext)         return 0;      if (strcasecmp (ext, ".gz") == 0 && ext > fname)         do            --ext;         while (ext > fname && ext [0] != '.');       if (strcasecmp (ext, ".ttc") != 0 &&          strcasecmp (ext, ".ttf") != 0 &&          strcasecmp (ext, ".otf") != 0 &&          strcasecmp (ext, ".pcf") != 0 &&          strcasecmp (ext, ".pcf.gz") != 0)         return 0;       // Filter by font name      if (strncasecmp (fname, sstate.fontname, sstate.fontnamelen) != 0)         return 0;       // At this point we only need to consider the mid part between font name      // and extension. This is either matched to one of the face variants,      // or we reject the file.      const char* mid = fname + sstate.fontnamelen;      size_t midlen = ext - mid;       // Discard optional hyphen, underscore or space between name and midpart      if (midlen > 0 &&          (mid [0] == '-' || mid [0] == '_' || mid [0] == ' '))      {         ++mid;         --midlen;      }       // Apply some simple heuristics to identify font variants      if (midlen == 0 ||          strncasecmp (mid, "R", midlen) == 0 ||          strncasecmp (mid, "Regular", midlen) == 0)      {         if (saveCandidate (fpath, ext, ftwbuf->level,                            "Regular", sstate.regular))            return 0;      }      else if (strncasecmp (mid, "B", midlen) == 0 ||               strncasecmp (mid, "Bold", midlen) == 0)      {         if (saveCandidate (fpath, ext, ftwbuf->level,                            "Bold", sstate.bold))            return 0;      }      else if (strncasecmp (mid, "I", midlen) == 0 ||               strncasecmp (mid, "It", midlen) == 0 ||               strncasecmp (mid, "Italic", midlen) == 0 ||               strncasecmp (mid, "O", midlen) == 0 ||               strncasecmp (mid, "Ob", midlen) == 0 ||               strncasecmp (mid, "Oblique", midlen) == 0)      {         if (saveCandidate (fpath, ext, ftwbuf->level,                            "Italic", sstate.italic))            return 0;      }      else if (strncasecmp (mid, "BI", midlen) == 0 ||               strncasecmp (mid, "BoldIt", midlen) == 0 ||               strncasecmp (mid, "BoldItalic", midlen) == 0)      {         if (saveCandidate (fpath, ext, ftwbuf->level,                            "BoldItalic", sstate.boldItalic))            return 0;      }    #if 0      // TODO remove the below printouts along with the include of stdio.h      printf("%-3s %2d ",             (tflag == FTW_D) ?   "d"   : (tflag == FTW_DNR) ? "dnr" :             (tflag == FTW_DP) ?  "dp"  : (tflag == FTW_F) ?   "f" :             (tflag == FTW_NS) ?  "ns"  : (tflag == FTW_SL) ?  "sl" :             (tflag == FTW_SLN) ? "sln" : "???",             ftwbuf->level);       if (tflag == FTW_NS)         printf("-------");      else         printf("%7jd", (intmax_t) sb->st_size);       printf("   %-40s %d %s\n",             fpath, ftwbuf->base, fpath + ftwbuf->base);   #endif      return 0;   } } // namespace namespace zutty{   Fontpack::Fontpack (const std::string& fontpath,                       const std::string& fontname,                       const std::string& dwfontname)   {      logT << "Fontpack: fontpath=" << fontpath           << "; fontname=" << fontname           << "; dwfontname=" << dwfontname           << std::endl;       // Look for & initialize the regular font (with variants)       sstate.fontname = fontname.data ();      sstate.fontnamelen = fontname.size ();       size_t pos = 0;      size_t nextpos = 0;      do      {         nextpos = fontpath.find (':', pos);         size_t len = (nextpos == std::string::npos)                    ? std::string::npos                    : nextpos - pos;          std::string fontpath1 = fontpath.substr (pos, len);         logT << "Looking for candidates under " << fontpath1 << std::endl;         pos = nextpos + 1;          int flags = FTW_DEPTH;         if (nftw (fontpath1.c_str (), fontFileFilter, 32, flags) == -1)         {            SYS_WARN ("Cannot walk file tree at ", fontpath1);         }       } while (!sstate.regular.size () && nextpos != std::string::npos);       if (! sstate.regular.size ())      {         logE << "No Regular variant of the requested font '" << fontname              << "' could be identified." << std::endl;         throw std::runtime_error (std::string ("No suitable files for '") +                                   fontname + "' found!");      }       fontRegular = std::make_unique <Font> (sstate.regular);      px = fontRegular->getPx ();      py = fontRegular->getPy ();       try      {         if (sstate.bold.size ())            fontBold = std::make_unique <Font> (               sstate.bold, * fontRegular.get (), Font::Overlay);      }      catch (const std::runtime_error& e)      {         fontBold = nullptr;         logW << "Failed to load bold variant: " << e.what () << std::endl;      }       try      {         if (sstate.italic.size ())            fontItalic = std::make_unique <Font> (               sstate.italic, * fontRegular.get (), Font::Overlay);      }      catch (const std::runtime_error& e)      {         fontItalic = nullptr;         logW << "Failed to load italic variant: " << e.what () << std::endl;      }       try      {         if (sstate.boldItalic.size ())            fontBoldItalic = std::make_unique <Font> (               sstate.boldItalic, * fontRegular.get (), Font::Overlay);      }      catch (const std::runtime_error& e)      {         fontBoldItalic = nullptr;         logW << "Failed to load boldItalic variant: " << e.what () << std::endl;      }       // Initialize the underline metrics       ulMetrics [0] = getRegular().getUlTop ();      ulMetrics [1] = getRegular().getUlThick ();      ulMetrics [2] = getBold().getUlTop ();      ulMetrics [3] = getBold().getUlThick ();      ulMetrics [4] = getItalic().getUlTop ();      ulMetrics [5] = getItalic().getUlThick ();      ulMetrics [6] = getBoldItalic().getUlTop ();      ulMetrics [7] = getBoldItalic().getUlThick ();       // Look for & initialize the double-width font       sstate.level = 0;      sstate.ext = "";      sstate.regular = "";      sstate.bold = "";      sstate.italic = "";      sstate.boldItalic = "";       sstate.fontname = dwfontname.data ();      sstate.fontnamelen = dwfontname.size ();       pos = 0;      nextpos = 0;      do      {         nextpos = fontpath.find (':', pos);         size_t len = (nextpos == std::string::npos)                    ? std::string::npos                    : nextpos - pos;          std::string fontpath1 = fontpath.substr (pos, len);         logT << "Looking for double-width candidates under " << fontpath1              << std::endl;         pos = nextpos + 1;          int flags = FTW_DEPTH;         if (nftw (fontpath1.c_str (), fontFileFilter, 32, flags) == -1)         {            SYS_WARN ("Cannot walk file tree at ", fontpath1);         }       } while (!sstate.regular.size () && nextpos != std::string::npos);       try      {         if (sstate.regular.size ())            fontDoubleWidth = std::make_unique <Font> (               sstate.regular, * fontRegular.get (), Font::DoubleWidth);         else if (dwfontname != "")         {            logW << "Failed to locate requested double-width font: "                 << dwfontname << std::endl;         }      }      catch (const std::runtime_error& e)      {         fontDoubleWidth = nullptr;         logW << "Failed to load double-width font: " << e.what () << std::endl;      }   } } // namespace zutty

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t