// Copyright (c) 2012, Thomas Goyne // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. // // Aegisub Project http://www.aegisub.org/ #include #include #include #include #include #include #include #include #include class AssDialogue; class AssFile; typedef std::function FontCollectorStatusCallback; struct CollectionResult { /// Characters which could not be found in any font files wxString missing; /// Paths to the file(s) containing the requested font std::vector paths; bool fake_bold = false; bool fake_italic = false; }; #ifdef _WIN32 class GdiFontFileLister { std::unordered_multimap index; agi::scoped_holder dc; std::string buffer; bool ProcessLogFont(LOGFONTW const& expected, LOGFONTW const& actual, std::vector const& characters); public: /// Constructor /// @param cb Callback for status logging GdiFontFileLister(FontCollectorStatusCallback &cb); /// @brief Get the path to the font with the given styles /// @param facename Name of font face /// @param bold ASS font weight /// @param italic Italic? /// @param characters Characters in this style /// @return Path to the matching font file(s), or empty if not found CollectionResult GetFontPaths(std::string const& facename, int bold, bool italic, std::vector const& characters); }; using FontFileLister = GdiFontFileLister; #elif defined(__APPLE__) struct CoreTextFontFileLister { CoreTextFontFileLister(FontCollectorStatusCallback &) {} /// @brief Get the path to the font with the given styles /// @param facename Name of font face /// @param bold ASS font weight /// @param italic Italic? /// @param characters Characters in this style /// @return Path to the matching font file(s), or empty if not found CollectionResult GetFontPaths(std::string const& facename, int bold, bool italic, std::vector const& characters); }; using FontFileLister = CoreTextFontFileLister; #else typedef struct _FcConfig FcConfig; typedef struct _FcFontSet FcFontSet; /// @class FontConfigFontFileLister /// @brief fontconfig powered font lister class FontConfigFontFileLister { agi::scoped_holder config; /// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans") /// @param family font fullname /// @param bold weight attribute /// @param italic italic attribute /// @return font set FcFontSet *MatchFullname(const char *family, int weight, int slant); public: /// Constructor /// @param cb Callback for status logging FontConfigFontFileLister(FontCollectorStatusCallback &cb); /// @brief Get the path to the font with the given styles /// @param facename Name of font face /// @param bold ASS font weight /// @param italic Italic? /// @param characters Characters in this style /// @return Path to the matching font file(s), or empty if not found CollectionResult GetFontPaths(std::string const& facename, int bold, bool italic, std::vector const& characters); }; using FontFileLister = FontConfigFontFileLister; #endif /// @class FontCollector /// @brief Class which collects the paths to all fonts used in a script class FontCollector { /// All data needed to find the font file used to render text struct StyleInfo { std::string facename; int bold; bool italic; bool operator<(StyleInfo const& rgt) const; }; /// Data about where each style is used struct UsageData { std::vector chars; ///< Characters used in this style which glyphs will be needed for std::vector lines; ///< Lines on which this style is used via overrides std::vector styles; ///< ASS styles which use this style }; /// Message callback provider by caller FontCollectorStatusCallback status_callback; FontFileLister lister; /// The set of all glyphs used in the file std::map used_styles; /// Style name -> ASS style definition std::map styles; /// Paths to found required font files std::vector results; /// Number of fonts which could not be found int missing = 0; /// Number of fonts which were found, but did not contain all used glyphs int missing_glyphs = 0; /// Gather all of the unique styles with text on a line void ProcessDialogueLine(const AssDialogue *line, int index); /// Get the font for a single style void ProcessChunk(std::pair const& style); /// Print the lines and styles on which a missing font is used void PrintUsage(UsageData const& data); public: /// Constructor /// @param status_callback Function to pass status updates to /// @param lister The actual font file lister FontCollector(FontCollectorStatusCallback status_callback); /// @brief Get a list of the locations of all font files used in the file /// @param file Lines in the subtitle file to check /// @param status Callback function for messages /// @return List of paths to fonts std::vector GetFontPaths(const AssFile *file); };