~ubuntu-branches/ubuntu/wily/aegisub/wily-proposed

« back to all changes in this revision

Viewing changes to src/font_file_lister.cpp

  • Committer: Package Import Robot
  • Author(s): Sebastian Reichel, Pascal De Vuyst, Juan Picca, Sebastian Reichel
  • Date: 2015-08-04 21:40:50 UTC
  • mfrom: (5.1.1 sid)
  • Revision ID: package-import@ubuntu.com-20150804214050-y2aghm9vdksoc8t7
Tags: 3.2.2+dfsg-1
[ Pascal De Vuyst ]
* Fix Typo in package description (Closes: #739219)

[ Juan Picca ]
* Add patch to fix reproducible build (Closes: #789728)

[ Sebastian Reichel ]
* New upstream release
 - remove vendor directory from orig tarball
* Update Debian Standards Version to 3.9.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
//
15
15
// Aegisub Project http://www.aegisub.org/
16
16
 
17
 
/// @file font_file_lister.cpp
18
 
/// @brief Base-class for font collector implementations
19
 
/// @ingroup font_collector
20
 
///
21
 
 
22
 
#include "config.h"
23
 
 
24
17
#include "font_file_lister.h"
25
18
 
26
19
#include "ass_dialogue.h"
27
20
#include "ass_file.h"
28
21
#include "ass_style.h"
29
22
#include "compat.h"
30
 
#include "utils.h"
 
23
#include "format.h"
31
24
 
32
 
#include <libaegisub/of_type_adaptor.h>
 
25
#include <libaegisub/format_flyweight.h>
 
26
#include <libaegisub/format_path.h>
33
27
 
34
28
#include <algorithm>
35
29
#include <tuple>
36
30
#include <unicode/uchar.h>
37
31
#include <wx/intl.h>
38
32
 
39
 
using namespace std::placeholders;
40
 
 
41
33
namespace {
42
 
        wxString format_missing(wxString const& str) {
43
 
                wxString printable;
44
 
                wxString unprintable;
45
 
                for (wxUniChar c : str) {
46
 
                        if (!u_isUWhiteSpace(c.GetValue()))
47
 
                                printable += c;
48
 
                        else {
49
 
                                unprintable += wxString::Format("\n - U+%04X ", c.GetValue());
50
 
                                UErrorCode ec;
51
 
                                char buf[1024];
52
 
                                auto len = u_charName(c.GetValue(), U_EXTENDED_CHAR_NAME, buf, sizeof buf, &ec);
53
 
                                if (len != 0 && U_SUCCESS(ec))
54
 
                                        unprintable += to_wx(buf);
55
 
                                if (c.GetValue() == 0xA0)
56
 
                                        unprintable += " (\\h)";
57
 
                        }
 
34
wxString format_missing(wxString const& str) {
 
35
        wxString printable;
 
36
        wxString unprintable;
 
37
        for (wxUniChar c : str) {
 
38
                if (!u_isUWhiteSpace(c.GetValue()))
 
39
                        printable += c;
 
40
                else {
 
41
                        unprintable += fmt_wx("\n - U+%04X ", c.GetValue());
 
42
                        UErrorCode ec;
 
43
                        char buf[1024];
 
44
                        auto len = u_charName(c.GetValue(), U_EXTENDED_CHAR_NAME, buf, sizeof buf, &ec);
 
45
                        if (len != 0 && U_SUCCESS(ec))
 
46
                                unprintable += to_wx(buf);
 
47
                        if (c.GetValue() == 0xA0)
 
48
                                unprintable += " (\\h)";
58
49
                }
59
 
 
60
 
                return printable + unprintable;
61
50
        }
62
 
}
63
 
 
64
 
FontCollector::FontCollector(FontCollectorStatusCallback status_callback, FontFileLister &lister)
 
51
 
 
52
        return printable + unprintable;
 
53
}
 
54
}
 
55
 
 
56
FontCollector::FontCollector(FontCollectorStatusCallback status_callback)
65
57
: status_callback(std::move(status_callback))
66
 
, lister(lister)
 
58
, lister(this->status_callback)
67
59
{
68
60
}
69
61
 
72
64
 
73
65
        auto style_it = styles.find(line->Style);
74
66
        if (style_it == end(styles)) {
75
 
                status_callback(wxString::Format(_("Style '%s' does not exist\n"), to_wx(line->Style)), 2);
 
67
                status_callback(fmt_tl("Style '%s' does not exist\n", line->Style), 2);
76
68
                ++missing;
77
69
                return;
78
70
        }
79
71
 
80
 
        boost::ptr_vector<AssDialogueBlock> blocks(line->ParseTags());
81
72
        StyleInfo style = style_it->second;
82
73
        StyleInfo initial = style;
83
74
 
84
75
        bool overriden = false;
85
76
 
86
 
        for (auto& block : blocks) {
87
 
                if (AssDialogueBlockOverride *ovr = dynamic_cast<AssDialogueBlockOverride *>(&block)) {
 
77
        for (auto& block : line->ParseTags()) {
 
78
                if (auto ovr = dynamic_cast<AssDialogueBlockOverride *>(block.get())) {
88
79
                        for (auto const& tag : ovr->Tags) {
89
 
                                std::string const& name = tag.Name;
90
 
 
91
 
                                if (name == "\\r") {
 
80
                                if (tag.Name == "\\r") {
92
81
                                        style = styles[tag.Params[0].Get(line->Style.get())];
93
82
                                        overriden = false;
94
83
                                }
95
 
                                else if (name == "\\b") {
 
84
                                else if (tag.Name == "\\b") {
96
85
                                        style.bold = tag.Params[0].Get(initial.bold);
97
86
                                        overriden = true;
98
87
                                }
99
 
                                else if (name == "\\i") {
 
88
                                else if (tag.Name == "\\i") {
100
89
                                        style.italic = tag.Params[0].Get(initial.italic);
101
90
                                        overriden = true;
102
91
                                }
103
 
                                else if (name == "\\fn") {
 
92
                                else if (tag.Name == "\\fn") {
104
93
                                        style.facename = tag.Params[0].Get(initial.facename);
105
94
                                        overriden = true;
106
95
                                }
107
96
                        }
108
97
                }
109
 
                else if (AssDialogueBlockPlain *txt = dynamic_cast<AssDialogueBlockPlain *>(&block)) {
110
 
                        wxString text(to_wx(txt->GetText()));
 
98
                else if (auto txt = dynamic_cast<AssDialogueBlockPlain *>(block.get())) {
 
99
                        auto text = txt->GetText();
111
100
 
112
101
                        if (text.empty())
113
102
                                continue;
114
103
 
115
 
                        if (overriden)
116
 
                                used_styles[style].lines.insert(index);
117
 
                        std::set<wxUniChar>& chars = used_styles[style].chars;
118
 
                        for (auto it = text.begin(); it != text.end(); ++it) {
119
 
                                wxUniChar cur = *it;
120
 
                                if (cur == L'\\' && it + 1 != text.end()) {
121
 
                                        wxUniChar next = *++it;
122
 
                                        if (next == 'N' || next == 'n')
123
 
                                                continue;
124
 
                                        if (next == 'h')
125
 
                                                cur = 0xA0;
126
 
                                        else
127
 
                                                --it;
 
104
                        auto& usage = used_styles[style];
 
105
 
 
106
                        if (overriden) {
 
107
                                auto& lines = usage.lines;
 
108
                                if (lines.empty() || lines.back() != index)
 
109
                                        lines.push_back(index);
 
110
                        }
 
111
 
 
112
                        auto& chars = usage.chars;
 
113
                        auto size = static_cast<int>(text.size());
 
114
                        for (int i = 0; i < size; ) {
 
115
                                if (text[i] == '\\' && i + 1 < size) {
 
116
                                        char next = text[++i];
 
117
                                        if (next == 'N' || next == 'n') {
 
118
                                                ++i;
 
119
                                                continue;
 
120
                                        }
 
121
                                        if (next == 'h') {
 
122
                                                ++i;
 
123
                                                chars.push_back(0xA0);
 
124
                                                continue;
 
125
                                        }
 
126
 
 
127
                                        chars.push_back('\\');
 
128
                                        continue;
128
129
                                }
129
 
                                chars.insert(cur);
 
130
 
 
131
                                UChar32 c;
 
132
                                U8_NEXT(&text[0], i, size, c);
 
133
                                chars.push_back(c);
130
134
                        }
 
135
 
 
136
                        sort(begin(chars), end(chars));
 
137
                        chars.erase(unique(chars.begin(), chars.end()), chars.end());
131
138
                }
132
139
                // Do nothing with drawing and comment blocks
133
140
        }
136
143
void FontCollector::ProcessChunk(std::pair<StyleInfo, UsageData> const& style) {
137
144
        if (style.second.chars.empty()) return;
138
145
 
139
 
        FontFileLister::CollectionResult res = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second.chars);
 
146
        auto res = lister.GetFontPaths(style.first.facename, style.first.bold, style.first.italic, style.second.chars);
140
147
 
141
148
        if (res.paths.empty()) {
142
 
                status_callback(wxString::Format(_("Could not find font '%s'\n"), to_wx(style.first.facename)), 2);
 
149
                status_callback(fmt_tl("Could not find font '%s'\n", style.first.facename), 2);
143
150
                PrintUsage(style.second);
144
151
                ++missing;
145
152
        }
146
153
        else {
147
154
                for (auto& elem : res.paths) {
148
 
                        if (results.insert(elem).second)
149
 
                                status_callback(wxString::Format(_("Found '%s' at '%s'\n"), to_wx(style.first.facename), elem.make_preferred().wstring()), 0);
 
155
                        elem.make_preferred();
 
156
                        if (std::find(begin(results), end(results), elem) == end(results)) {
 
157
                                status_callback(fmt_tl("Found '%s' at '%s'\n", style.first.facename, elem), 0);
 
158
                                results.push_back(elem);
 
159
                        }
150
160
                }
151
161
 
 
162
                if (res.fake_bold)
 
163
                        status_callback(fmt_tl("'%s' does not have a bold variant.\n", style.first.facename), 3);
 
164
                if (res.fake_italic)
 
165
                        status_callback(fmt_tl("'%s' does not have an italic variant.\n", style.first.facename), 3);
 
166
 
152
167
                if (res.missing.size()) {
153
168
                        if (res.missing.size() > 50)
154
 
                                status_callback(wxString::Format(_("'%s' is missing %d glyphs used.\n"), to_wx(style.first.facename), (int)res.missing.size()), 2);
 
169
                                status_callback(fmt_tl("'%s' is missing %d glyphs used.\n", style.first.facename, res.missing.size()), 2);
155
170
                        else if (res.missing.size() > 0)
156
 
                                status_callback(wxString::Format(_("'%s' is missing the following glyphs used: %s\n"), to_wx(style.first.facename), format_missing(res.missing)), 2);
 
171
                                status_callback(fmt_tl("'%s' is missing the following glyphs used: %s\n", style.first.facename, format_missing(res.missing)), 2);
157
172
                        PrintUsage(style.second);
158
173
                        ++missing_glyphs;
159
174
                }
 
175
                else if (res.fake_bold || res.fake_italic)
 
176
                        PrintUsage(style.second);
160
177
        }
161
178
}
162
179
 
163
180
void FontCollector::PrintUsage(UsageData const& data) {
164
181
        if (data.styles.size()) {
165
 
                status_callback(wxString::Format(_("Used in styles:\n")), 2);
 
182
                status_callback(_("Used in styles:\n"), 2);
166
183
                for (auto const& style : data.styles)
167
 
                        status_callback(wxString::Format("  - %s\n", style), 2);
 
184
                        status_callback(fmt_wx("  - %s\n", style), 2);
168
185
        }
169
186
 
170
187
        if (data.lines.size()) {
171
 
                status_callback(wxString::Format(_("Used on lines:")), 2);
 
188
                status_callback(_("Used on lines:"), 2);
172
189
                for (int line : data.lines)
173
 
                        status_callback(wxString::Format(" %d", line), 2);
 
190
                        status_callback(fmt_wx(" %d", line), 2);
174
191
                status_callback("\n", 2);
175
192
        }
176
193
        status_callback("\n", 2);
182
199
 
183
200
        status_callback(_("Parsing file\n"), 0);
184
201
 
185
 
        for (auto style : file->Line | agi::of_type<const AssStyle>()) {
186
 
                StyleInfo &info = styles[style->name];
187
 
                info.facename = style->font;
188
 
                info.bold     = style->bold;
189
 
                info.italic   = style->italic;
190
 
                used_styles[info].styles.insert(style->name);
 
202
        for (auto const& style : file->Styles) {
 
203
                StyleInfo &info = styles[style.name];
 
204
                info.facename = style.font;
 
205
                info.bold     = style.bold;
 
206
                info.italic   = style.italic;
 
207
                used_styles[info].styles.push_back(style.name);
191
208
        }
192
209
 
193
210
        int index = 0;
194
 
        for (auto diag : file->Line | agi::of_type<const AssDialogue>())
195
 
                ProcessDialogueLine(diag, ++index);
 
211
        for (auto const& diag : file->Events)
 
212
                ProcessDialogueLine(&diag, ++index);
196
213
 
197
214
        status_callback(_("Searching for font files\n"), 0);
198
 
        for_each(used_styles.begin(), used_styles.end(), bind(&FontCollector::ProcessChunk, this, _1));
 
215
        for (auto const& style : used_styles) ProcessChunk(style);
199
216
        status_callback(_("Done\n\n"), 0);
200
217
 
201
218
        std::vector<agi::fs::path> paths;
205
222
        if (missing == 0)
206
223
                status_callback(_("All fonts found.\n"), 1);
207
224
        else
208
 
                status_callback(wxString::Format(_("%d fonts could not be found.\n"), missing), 2);
 
225
                status_callback(fmt_plural(missing, "One font could not be found\n", "%d fonts could not be found.\n", missing), 2);
209
226
        if (missing_glyphs != 0)
210
 
                status_callback(wxString::Format(_("%d fonts were found, but were missing glyphs used in the script.\n"), missing_glyphs), 2);
 
227
                status_callback(fmt_plural(missing_glyphs,
 
228
                        "One font was found, but was missing glyphs used in the script.\n",
 
229
                        "%d fonts were found, but were missing glyphs used in the script.\n",
 
230
                        missing_glyphs), 2);
211
231
 
212
232
        return paths;
213
233
}