From 6652ef40e99a53db4be34fca69005a55e680a6d6 Mon Sep 17 00:00:00 2001 From: Thomas Goyne Date: Thu, 2 Feb 2012 19:18:40 +0000 Subject: [PATCH] Increase the amount of information reported when fonts can't be found List the styles using the font along with lines which use the font via overrides, and add a warning at the end when some glyphs could not be found to reduce the chance of the user failing to notice it. Originally committed to SVN as r6434. --- aegisub/src/font_file_lister.cpp | 79 +++++++++++++++------ aegisub/src/font_file_lister.h | 29 ++++++-- aegisub/src/font_file_lister_fontconfig.cpp | 16 ++--- aegisub/src/font_file_lister_fontconfig.h | 3 +- aegisub/src/font_file_lister_freetype.cpp | 10 +-- aegisub/src/font_file_lister_freetype.h | 2 +- 6 files changed, 94 insertions(+), 45 deletions(-) diff --git a/aegisub/src/font_file_lister.cpp b/aegisub/src/font_file_lister.cpp index 04f97cfff..025159aa6 100644 --- a/aegisub/src/font_file_lister.cpp +++ b/aegisub/src/font_file_lister.cpp @@ -43,35 +43,45 @@ FontCollector::FontCollector(FontCollectorStatusCallback status_callback, FontFi { } -void FontCollector::ProcessDialogueLine(AssDialogue *line) { +void FontCollector::ProcessDialogueLine(AssDialogue *line, int index) { if (line->Comment) return; line->ParseASSTags(); StyleInfo style = styles[line->Style]; StyleInfo initial = style; + bool overriden = false; + for (size_t i = 0; i < line->Blocks.size(); ++i) { if (AssDialogueBlockOverride *ovr = dynamic_cast(line->Blocks[i])) { for (size_t j = 0; j < ovr->Tags.size(); ++j) { AssOverrideTag *tag = ovr->Tags[j]; wxString name = tag->Name; - if (name == "\\r") + if (name == "\\r") { style = styles[tag->Params[0]->Get(line->Style)]; - if (name == "\\b") + overriden = false; + } + else if (name == "\\b") { style.bold = tag->Params[0]->Get(initial.bold); - else if (name == "\\i") + overriden = true; + } + else if (name == "\\i") { style.italic = tag->Params[0]->Get(initial.italic); - else if (name == "\\fn") + overriden = true; + } + else if (name == "\\fn") { style.facename = tag->Params[0]->Get(initial.facename); - else - continue; + overriden = true; + } } } else if (AssDialogueBlockPlain *txt = dynamic_cast(line->Blocks[i])) { wxString text = txt->GetText(); if (text.size()) { - std::set& chars = used_styles[style]; + if (overriden) + used_styles[style].lines.insert(index); + std::set& chars = used_styles[style].chars; for (size_t i = 0; i < text.size(); ++i) chars.insert(text[i]); } @@ -81,39 +91,64 @@ void FontCollector::ProcessDialogueLine(AssDialogue *line) { line->ClearBlocks(); } -void FontCollector::ProcessChunk(std::pair > const& style) { - std::vector paths = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second); +void FontCollector::ProcessChunk(std::pair const& style) { + FontFileLister::CollectionResult res = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second.chars); - if (paths.empty()) { - status_callback(wxString::Format("Could not find font '%s'\n", style.first.facename), 2); + if (res.paths.empty()) { + status_callback(wxString::Format(_("Could not find font '%s'\n"), style.first.facename), 2); + PrintUsage(style.second); ++missing; } else { - for (size_t i = 0; i < paths.size(); ++i) { - if (results.insert(paths[i]).second) - status_callback(wxString::Format("Found '%s' at '%s'\n", style.first.facename, paths[i]), 0); + for (size_t i = 0; i < res.paths.size(); ++i) { + if (results.insert(res.paths[i]).second) + status_callback(wxString::Format(_("Found '%s' at '%s'\n"), style.first.facename, res.paths[i]), 0); + } + + if (res.missing.size()) { + if (res.missing.size() > 50) + status_callback(wxString::Format(_("'%s' is missing %d glyphs used.\n"), style.first.facename, (int)res.missing.size()), 2); + else if (res.missing.size() > 0) + status_callback(wxString::Format(_("'%s' is missing the following glyphs used: %s\n"), style.first.facename, res.missing), 2); + PrintUsage(style.second); + ++missing_glyphs; } } } +void FontCollector::PrintUsage(UsageData const& data) { + if (data.styles.size()) { + status_callback(wxString::Format(_("Used in styles:\n")), 2); + for (std::set::const_iterator it = data.styles.begin(); it != data.styles.end(); ++it) + status_callback(wxString::Format(" - %s\n", *it), 2); + } + + if (data.lines.size()) { + status_callback(wxString::Format(_("Used on lines:")), 2); + for (std::set::const_iterator it = data.lines.begin(); it != data.lines.end(); ++it) + status_callback(wxString::Format(" %d", *it), 2); + status_callback("\n", 2); + } + status_callback("\n", 2); +} + std::vector FontCollector::GetFontPaths(std::list const& file) { missing = 0; + missing_glyphs = 0; status_callback(_("Parsing file\n"), 0); + + int index = 0; for (std::list::const_iterator cur = file.begin(); cur != file.end(); ++cur) { if (AssStyle *style = dynamic_cast(*cur)) { StyleInfo &info = styles[style->name]; info.facename = style->font; info.bold = style->bold; info.italic = style->italic; + used_styles[info].styles.insert(style->name); } else if (AssDialogue *diag = dynamic_cast(*cur)) - ProcessDialogueLine(diag); - } - - if (used_styles.empty()) { - status_callback(_("No non-empty dialogue lines found"), 2); - return std::vector(); + ProcessDialogueLine(diag, ++index); } status_callback(_("Searching for font files\n"), 0); @@ -128,6 +163,8 @@ std::vector FontCollector::GetFontPaths(std::list const& fi status_callback(_("All fonts found.\n"), 1); else status_callback(wxString::Format(_("%d fonts could not be found.\n"), missing), 2); + if (missing_glyphs != 0) + status_callback(wxString::Format(_("%d fonts were found, but were missing glyphs used in the script.\n"), missing_glyphs), 2); return paths; } diff --git a/aegisub/src/font_file_lister.h b/aegisub/src/font_file_lister.h index 9dfe2eec6..a9399757b 100644 --- a/aegisub/src/font_file_lister.h +++ b/aegisub/src/font_file_lister.h @@ -42,18 +42,26 @@ typedef std::tr1::function FontCollectorStatusCallback; /// @brief Font lister interface class FontFileLister { public: + 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; + }; + /// @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 - virtual std::vector GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters) = 0; + virtual CollectionResult GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters) = 0; }; /// @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 { wxString facename; int bold; @@ -61,24 +69,37 @@ class FontCollector { bool operator<(StyleInfo const& rgt) const; }; + /// Data about where each style is used + struct UsageData { + std::set chars; ///< Characters used in this style which glyphs will be needed for + std::set lines; ///< Lines on which this style is used via overrides + std::set styles; ///< ASS styles which use this style + }; + /// Message callback provider by caller FontCollectorStatusCallback status_callback; /// The actual lister to use to get font paths FontFileLister &lister; /// The set of all glyphs used in the file - std::map > used_styles; + std::map used_styles; /// Style name -> ASS style definition std::map styles; /// Paths to found required font files std::set results; /// Number of fonts which could not be found int missing; + /// Number of fonts which were found, but did not contain all used glyphs + int missing_glyphs; /// Gather all of the unique styles with text on a line - void ProcessDialogueLine(AssDialogue *line); + void ProcessDialogueLine(AssDialogue *line, int index); + /// Get the font for a single style - void ProcessChunk(std::pair > const& 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 diff --git a/aegisub/src/font_file_lister_fontconfig.cpp b/aegisub/src/font_file_lister_fontconfig.cpp index 24d43a464..d82d6ffb5 100644 --- a/aegisub/src/font_file_lister_fontconfig.cpp +++ b/aegisub/src/font_file_lister_fontconfig.cpp @@ -71,7 +71,6 @@ namespace { FontConfigFontFileLister::FontConfigFontFileLister(FontCollectorStatusCallback cb) : config(FcInitLoadConfig(), FcConfigDestroy) -, cb(cb) { cb(_("Updating font cache\n"), 0); FcConfigBuildFonts(config); @@ -113,8 +112,8 @@ FcFontSet *FontConfigFontFileLister::MatchFullname(const char *family, int weigh return result; } -std::vector FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters) { - std::vector ret; +FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters) { + CollectionResult ret; std::string family = STD_STR(facename); if (family[0] == '@') @@ -188,22 +187,15 @@ std::vector FontConfigFontFileLister::GetFontPaths(wxString const& fac if(FcPatternGetString(rpat, FC_FILE, 0, &file) != FcResultMatch) return ret; - wxString missing; - FcCharSet *charset; if (FcPatternGetCharSet(rpat, FC_CHARSET, 0, &charset) == FcResultMatch) { for (std::set::const_iterator it = characters.begin(); it != characters.end(); ++it) { if (!FcCharSetHasChar(charset, *it)) - missing += *it; + ret.missing += *it; } } - if (missing.size() > 50) - cb(wxString::Format(_("'%s' is missing %d glyphs used.\n"), facename, (int)missing.size()), 2); - else if (missing.size() > 0) - cb(wxString::Format(_("'%s' is missing the following glyphs used: %s\n"), facename, missing), 2); - - ret.push_back((const char *)file); + ret.paths.push_back((const char *)file); return ret; } #endif diff --git a/aegisub/src/font_file_lister_fontconfig.h b/aegisub/src/font_file_lister_fontconfig.h index ce7e2963d..9d6255dd3 100644 --- a/aegisub/src/font_file_lister_fontconfig.h +++ b/aegisub/src/font_file_lister_fontconfig.h @@ -42,7 +42,6 @@ class FontConfigFontFileLister : public FontFileLister { }; scoped config; - FontCollectorStatusCallback cb; /// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans") /// @param family font fullname @@ -55,7 +54,7 @@ public: /// @param cb Callback for status logging FontConfigFontFileLister(FontCollectorStatusCallback cb); - std::vector GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters); + CollectionResult GetFontPaths(wxString const& facename, int bold, bool italic, std::set const& characters); }; #endif diff --git a/aegisub/src/font_file_lister_freetype.cpp b/aegisub/src/font_file_lister_freetype.cpp index 82d2a64d8..7460175b4 100644 --- a/aegisub/src/font_file_lister_freetype.cpp +++ b/aegisub/src/font_file_lister_freetype.cpp @@ -171,11 +171,11 @@ void FreetypeFontFileLister::AddFont(wxString const& filename, wxString const& f AddFont(filename, "*" + family); } -std::vector FreetypeFontFileLister::GetFontPaths(wxString const& facename, int, bool, std::set const&) { - std::vector ret; - ret.insert(ret.end(), font_files[facename].begin(), font_files[facename].end()); - if (ret.empty()) - ret.insert(ret.end(), font_files["*" + facename].begin(), font_files["*" + facename].end()); +FontFileLister::CollectionResult FreetypeFontFileLister::GetFontPaths(wxString const& facename, int, bool, std::set const&) { + CollectionResult ret; + ret.paths.insert(ret.paths.end(), font_files[facename].begin(), font_files[facename].end()); + if (ret.paths.empty()) + ret.paths.insert(ret.paths.end(), font_files["*" + facename].begin(), font_files["*" + facename].end()); return ret; } diff --git a/aegisub/src/font_file_lister_freetype.h b/aegisub/src/font_file_lister_freetype.h index ac3748081..43e26327d 100644 --- a/aegisub/src/font_file_lister_freetype.h +++ b/aegisub/src/font_file_lister_freetype.h @@ -57,7 +57,7 @@ public: /// @param cb Callback for status logging FreetypeFontFileLister(FontCollectorStatusCallback cb); - std::vector GetFontPaths(wxString const& facename, int, bool, std::set const&); + CollectionResult GetFontPaths(wxString const& facename, int, bool, std::set const&); }; #endif