forked from mia/Aegisub
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;
|
if (line->Comment) return;
|
||||||
|
|
||||||
line->ParseASSTags();
|
line->ParseASSTags();
|
||||||
StyleInfo style = styles[line->Style];
|
StyleInfo style = styles[line->Style];
|
||||||
StyleInfo initial = style;
|
StyleInfo initial = style;
|
||||||
|
|
||||||
|
bool overriden = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < line->Blocks.size(); ++i) {
|
for (size_t i = 0; i < line->Blocks.size(); ++i) {
|
||||||
if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride *>(line->Blocks[i])) {
|
if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride *>(line->Blocks[i])) {
|
||||||
for (size_t j = 0; j < ovr->Tags.size(); ++j) {
|
for (size_t j = 0; j < ovr->Tags.size(); ++j) {
|
||||||
AssOverrideTag *tag = ovr->Tags[j];
|
AssOverrideTag *tag = ovr->Tags[j];
|
||||||
wxString name = tag->Name;
|
wxString name = tag->Name;
|
||||||
|
|
||||||
if (name == "\\r")
|
if (name == "\\r") {
|
||||||
style = styles[tag->Params[0]->Get(line->Style)];
|
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);
|
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);
|
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);
|
style.facename = tag->Params[0]->Get(initial.facename);
|
||||||
else
|
overriden = true;
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (AssDialogueBlockPlain *txt = dynamic_cast<AssDialogueBlockPlain *>(line->Blocks[i])) {
|
else if (AssDialogueBlockPlain *txt = dynamic_cast<AssDialogueBlockPlain *>(line->Blocks[i])) {
|
||||||
wxString text = txt->GetText();
|
wxString text = txt->GetText();
|
||||||
if (text.size()) {
|
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)
|
for (size_t i = 0; i < text.size(); ++i)
|
||||||
chars.insert(text[i]);
|
chars.insert(text[i]);
|
||||||
}
|
}
|
||||||
|
@ -81,39 +91,64 @@ void FontCollector::ProcessDialogueLine(AssDialogue *line) {
|
||||||
line->ClearBlocks();
|
line->ClearBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FontCollector::ProcessChunk(std::pair<StyleInfo, std::set<wxUniChar> > const& style) {
|
void FontCollector::ProcessChunk(std::pair<StyleInfo, UsageData> const& style) {
|
||||||
std::vector<wxString> paths = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second);
|
FontFileLister::CollectionResult res = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second.chars);
|
||||||
|
|
||||||
if (paths.empty()) {
|
if (res.paths.empty()) {
|
||||||
status_callback(wxString::Format("Could not find font '%s'\n", style.first.facename), 2);
|
status_callback(wxString::Format(_("Could not find font '%s'\n"), style.first.facename), 2);
|
||||||
|
PrintUsage(style.second);
|
||||||
++missing;
|
++missing;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (size_t i = 0; i < paths.size(); ++i) {
|
for (size_t i = 0; i < res.paths.size(); ++i) {
|
||||||
if (results.insert(paths[i]).second)
|
if (results.insert(res.paths[i]).second)
|
||||||
status_callback(wxString::Format("Found '%s' at '%s'\n", style.first.facename, paths[i]), 0);
|
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) {
|
std::vector<wxString> FontCollector::GetFontPaths(std::list<AssEntry*> const& file) {
|
||||||
missing = 0;
|
missing = 0;
|
||||||
|
missing_glyphs = 0;
|
||||||
|
|
||||||
status_callback(_("Parsing file\n"), 0);
|
status_callback(_("Parsing file\n"), 0);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
for (std::list<AssEntry*>::const_iterator cur = file.begin(); cur != file.end(); ++cur) {
|
for (std::list<AssEntry*>::const_iterator cur = file.begin(); cur != file.end(); ++cur) {
|
||||||
if (AssStyle *style = dynamic_cast<AssStyle*>(*cur)) {
|
if (AssStyle *style = dynamic_cast<AssStyle*>(*cur)) {
|
||||||
StyleInfo &info = styles[style->name];
|
StyleInfo &info = styles[style->name];
|
||||||
info.facename = style->font;
|
info.facename = style->font;
|
||||||
info.bold = style->bold;
|
info.bold = style->bold;
|
||||||
info.italic = style->italic;
|
info.italic = style->italic;
|
||||||
|
used_styles[info].styles.insert(style->name);
|
||||||
}
|
}
|
||||||
else if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur))
|
else if (AssDialogue *diag = dynamic_cast<AssDialogue*>(*cur))
|
||||||
ProcessDialogueLine(diag);
|
ProcessDialogueLine(diag, ++index);
|
||||||
}
|
|
||||||
|
|
||||||
if (used_styles.empty()) {
|
|
||||||
status_callback(_("No non-empty dialogue lines found"), 2);
|
|
||||||
return std::vector<wxString>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
status_callback(_("Searching for font files\n"), 0);
|
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);
|
status_callback(_("All fonts found.\n"), 1);
|
||||||
else
|
else
|
||||||
status_callback(wxString::Format(_("%d fonts could not be found.\n"), missing), 2);
|
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;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,18 +42,26 @@ typedef std::tr1::function<void (wxString, int)> FontCollectorStatusCallback;
|
||||||
/// @brief Font lister interface
|
/// @brief Font lister interface
|
||||||
class FontFileLister {
|
class FontFileLister {
|
||||||
public:
|
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
|
/// @brief Get the path to the font with the given styles
|
||||||
/// @param facename Name of font face
|
/// @param facename Name of font face
|
||||||
/// @param bold ASS font weight
|
/// @param bold ASS font weight
|
||||||
/// @param italic Italic?
|
/// @param italic Italic?
|
||||||
/// @param characters Characters in this style
|
/// @param characters Characters in this style
|
||||||
/// @return Path to the matching font file(s), or empty if not found
|
/// @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
|
/// @class FontCollector
|
||||||
/// @brief Class which collects the paths to all fonts used in a script
|
/// @brief Class which collects the paths to all fonts used in a script
|
||||||
class FontCollector {
|
class FontCollector {
|
||||||
|
/// All data needed to find the font file used to render text
|
||||||
struct StyleInfo {
|
struct StyleInfo {
|
||||||
wxString facename;
|
wxString facename;
|
||||||
int bold;
|
int bold;
|
||||||
|
@ -61,24 +69,37 @@ class FontCollector {
|
||||||
bool operator<(StyleInfo const& rgt) const;
|
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
|
/// Message callback provider by caller
|
||||||
FontCollectorStatusCallback status_callback;
|
FontCollectorStatusCallback status_callback;
|
||||||
/// The actual lister to use to get font paths
|
/// The actual lister to use to get font paths
|
||||||
FontFileLister &lister;
|
FontFileLister &lister;
|
||||||
|
|
||||||
/// The set of all glyphs used in the file
|
/// 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
|
/// Style name -> ASS style definition
|
||||||
std::map<wxString, StyleInfo> styles;
|
std::map<wxString, StyleInfo> styles;
|
||||||
/// Paths to found required font files
|
/// Paths to found required font files
|
||||||
std::set<wxString> results;
|
std::set<wxString> results;
|
||||||
/// Number of fonts which could not be found
|
/// Number of fonts which could not be found
|
||||||
int missing;
|
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
|
/// 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
|
/// 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:
|
public:
|
||||||
/// Constructor
|
/// Constructor
|
||||||
|
|
|
@ -71,7 +71,6 @@ namespace {
|
||||||
|
|
||||||
FontConfigFontFileLister::FontConfigFontFileLister(FontCollectorStatusCallback cb)
|
FontConfigFontFileLister::FontConfigFontFileLister(FontCollectorStatusCallback cb)
|
||||||
: config(FcInitLoadConfig(), FcConfigDestroy)
|
: config(FcInitLoadConfig(), FcConfigDestroy)
|
||||||
, cb(cb)
|
|
||||||
{
|
{
|
||||||
cb(_("Updating font cache\n"), 0);
|
cb(_("Updating font cache\n"), 0);
|
||||||
FcConfigBuildFonts(config);
|
FcConfigBuildFonts(config);
|
||||||
|
@ -113,8 +112,8 @@ FcFontSet *FontConfigFontFileLister::MatchFullname(const char *family, int weigh
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<wxString> FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) {
|
FontFileLister::CollectionResult FontConfigFontFileLister::GetFontPaths(wxString const& facename, int bold, bool italic, std::set<wxUniChar> const& characters) {
|
||||||
std::vector<wxString> ret;
|
CollectionResult ret;
|
||||||
|
|
||||||
std::string family = STD_STR(facename);
|
std::string family = STD_STR(facename);
|
||||||
if (family[0] == '@')
|
if (family[0] == '@')
|
||||||
|
@ -188,22 +187,15 @@ std::vector<wxString> FontConfigFontFileLister::GetFontPaths(wxString const& fac
|
||||||
if(FcPatternGetString(rpat, FC_FILE, 0, &file) != FcResultMatch)
|
if(FcPatternGetString(rpat, FC_FILE, 0, &file) != FcResultMatch)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
wxString missing;
|
|
||||||
|
|
||||||
FcCharSet *charset;
|
FcCharSet *charset;
|
||||||
if (FcPatternGetCharSet(rpat, FC_CHARSET, 0, &charset) == FcResultMatch) {
|
if (FcPatternGetCharSet(rpat, FC_CHARSET, 0, &charset) == FcResultMatch) {
|
||||||
for (std::set<wxUniChar>::const_iterator it = characters.begin(); it != characters.end(); ++it) {
|
for (std::set<wxUniChar>::const_iterator it = characters.begin(); it != characters.end(); ++it) {
|
||||||
if (!FcCharSetHasChar(charset, *it))
|
if (!FcCharSetHasChar(charset, *it))
|
||||||
missing += *it;
|
ret.missing += *it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (missing.size() > 50)
|
ret.paths.push_back((const char *)file);
|
||||||
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);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,7 +42,6 @@ class FontConfigFontFileLister : public FontFileLister {
|
||||||
};
|
};
|
||||||
|
|
||||||
scoped<FcConfig*> config;
|
scoped<FcConfig*> config;
|
||||||
FontCollectorStatusCallback cb;
|
|
||||||
|
|
||||||
/// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans")
|
/// @brief Case-insensitive match ASS/SSA font family against full name. (also known as "name for humans")
|
||||||
/// @param family font fullname
|
/// @param family font fullname
|
||||||
|
@ -55,7 +54,7 @@ public:
|
||||||
/// @param cb Callback for status logging
|
/// @param cb Callback for status logging
|
||||||
FontConfigFontFileLister(FontCollectorStatusCallback cb);
|
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
|
#endif
|
||||||
|
|
|
@ -171,11 +171,11 @@ void FreetypeFontFileLister::AddFont(wxString const& filename, wxString const& f
|
||||||
AddFont(filename, "*" + family);
|
AddFont(filename, "*" + family);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<wxString> FreetypeFontFileLister::GetFontPaths(wxString const& facename, int, bool, std::set<wxUniChar> const&) {
|
FontFileLister::CollectionResult FreetypeFontFileLister::GetFontPaths(wxString const& facename, int, bool, std::set<wxUniChar> const&) {
|
||||||
std::vector<wxString> ret;
|
CollectionResult ret;
|
||||||
ret.insert(ret.end(), font_files[facename].begin(), font_files[facename].end());
|
ret.paths.insert(ret.paths.end(), font_files[facename].begin(), font_files[facename].end());
|
||||||
if (ret.empty())
|
if (ret.paths.empty())
|
||||||
ret.insert(ret.end(), font_files["*" + facename].begin(), font_files["*" + facename].end());
|
ret.paths.insert(ret.paths.end(), font_files["*" + facename].begin(), font_files["*" + facename].end());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ public:
|
||||||
/// @param cb Callback for status logging
|
/// @param cb Callback for status logging
|
||||||
FreetypeFontFileLister(FontCollectorStatusCallback cb);
|
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
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue