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.
This commit is contained in:
parent
6c365f0e6a
commit
6652ef40e9
6 changed files with 94 additions and 45 deletions
|
@ -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<AssDialogueBlockOverride *>(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<AssDialogueBlockPlain *>(line->Blocks[i])) {
|
||||
wxString text = txt->GetText();
|
||||
if (text.size()) {
|
||||
std::set<wxUniChar>& chars = used_styles[style];
|
||||
if (overriden)
|
||||
used_styles[style].lines.insert(index);
|
||||
std::set<wxUniChar>& 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<StyleInfo, std::set<wxUniChar> > const& style) {
|
||||
std::vector<wxString> paths = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second);
|
||||
void FontCollector::ProcessChunk(std::pair<StyleInfo, UsageData> 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<wxString>::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<int>::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<wxString> FontCollector::GetFontPaths(std::list<AssEntry*> const& file) {
|
||||
missing = 0;
|
||||
missing_glyphs = 0;
|
||||
|
||||
status_callback(_("Parsing file\n"), 0);
|
||||
|
||||
int index = 0;
|
||||
for (std::list<AssEntry*>::const_iterator cur = file.begin(); cur != file.end(); ++cur) {
|
||||
if (AssStyle *style = dynamic_cast<AssStyle*>(*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<AssDialogue*>(*cur))
|
||||
ProcessDialogueLine(diag);
|
||||
}
|
||||
|
||||
if (used_styles.empty()) {
|
||||
status_callback(_("No non-empty dialogue lines found"), 2);
|
||||
return std::vector<wxString>();
|
||||
ProcessDialogueLine(diag, ++index);
|
||||
}
|
||||
|
||||
status_callback(_("Searching for font files\n"), 0);
|
||||
|
@ -128,6 +163,8 @@ std::vector<wxString> FontCollector::GetFontPaths(std::list<AssEntry*> 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;
|
||||
}
|
||||
|
|
|
@ -42,18 +42,26 @@ typedef std::tr1::function<void (wxString, int)> 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<wxString> 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<wxString> GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) = 0;
|
||||
virtual CollectionResult GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> 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<wxUniChar> chars; ///< Characters used in this style which glyphs will be needed for
|
||||
std::set<int> lines; ///< Lines on which this style is used via overrides
|
||||
std::set<wxString> 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<StyleInfo, std::set<wxUniChar> > used_styles;
|
||||
std::map<StyleInfo, UsageData> used_styles;
|
||||
/// Style name -> ASS style definition
|
||||
std::map<wxString, StyleInfo> styles;
|
||||
/// Paths to found required font files
|
||||
std::set<wxString> 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<StyleInfo, std::set<wxUniChar> > const& style);
|
||||
void ProcessChunk(std::pair<StyleInfo, UsageData> const& style);
|
||||
|
||||
/// Print the lines and styles on which a missing font is used
|
||||
void PrintUsage(UsageData const& data);
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
|
|
|
@ -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<wxString> FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) {
|
||||
std::vector<wxString> ret;
|
||||
FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) {
|
||||
CollectionResult ret;
|
||||
|
||||
std::string family = STD_STR(facename);
|
||||
if (family[0] == '@')
|
||||
|
@ -188,22 +187,15 @@ std::vector<wxString> 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<wxUniChar>::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
|
||||
|
|
|
@ -42,7 +42,6 @@ class FontConfigFontFileLister : public FontFileLister {
|
|||
};
|
||||
|
||||
scoped<FcConfig*> 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<wxString> GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters);
|
||||
CollectionResult GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -171,11 +171,11 @@ void FreetypeFontFileLister::AddFont(wxString const& filename, wxString const& f
|
|||
AddFont(filename, "*" + family);
|
||||
}
|
||||
|
||||
std::vector<wxString> FreetypeFontFileLister::GetFontPaths(wxString const& facename, int, bool, std::set<wxUniChar> const&) {
|
||||
std::vector<wxString> 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<wxUniChar> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ public:
|
|||
/// @param cb Callback for status logging
|
||||
FreetypeFontFileLister(FontCollectorStatusCallback cb);
|
||||
|
||||
std::vector<wxString> GetFontPaths(wxString const& facename, int, bool, std::set<wxUniChar> const&);
|
||||
CollectionResult GetFontPaths(wxString const& facename, int, bool, std::set<wxUniChar> const&);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue