Bump libdcp for new equality option.
[libsub.git] / test / ssa_reader_test.cc
1 /*
2     Copyright (C) 2016-2021 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20
21 #include "collect.h"
22 #include "compose.hpp"
23 #include "exceptions.h"
24 #include "ssa_reader.h"
25 #include "subtitle.h"
26 #include "test.h"
27 #include <boost/test/unit_test.hpp>
28 #include <boost/filesystem.hpp>
29 #include <cstdio>
30 #include <cmath>
31 #include <iostream>
32
33
34 using std::fabs;
35 using std::string;
36 using std::vector;
37
38
39 BOOST_AUTO_TEST_CASE (ssa_reader_test)
40 {
41         boost::filesystem::path p = private_test / "example.ssa";
42         FILE* f = fopen (p.string().c_str(), "r");
43         sub::SSAReader reader (f);
44         fclose (f);
45         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
46
47         auto i = subs.begin ();
48
49         /* Convert a font size in points to a proportional size for this file */
50         auto fs = [](int x) {
51                 return static_cast<float>(x) / 1024;
52         };
53
54         BOOST_REQUIRE (i != subs.end ());
55         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 40, 650));
56         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 41, 790));
57         auto j = i->lines.begin();
58         BOOST_REQUIRE (j != i->lines.end ());
59         BOOST_REQUIRE_EQUAL (j->blocks.size(), 1);
60         sub::Block b = j->blocks.front ();
61         BOOST_CHECK_EQUAL (b.text, "Et les enregistrements de ses ondes delta ?");
62         BOOST_CHECK_EQUAL (b.font.get(), "Wolf_Rain");
63         BOOST_CHECK_CLOSE(b.font_size.proportional().get(), fs(56), 0.1);
64         BOOST_CHECK_EQUAL (b.bold, false);
65         BOOST_CHECK_EQUAL (b.italic, false);
66         BOOST_CHECK_EQUAL (b.underline, false);
67         ++i;
68
69         BOOST_REQUIRE (i != subs.end ());
70         BOOST_CHECK_EQUAL (i->from, sub::Time::from_hms (0, 2, 42, 420));
71         BOOST_CHECK_EQUAL (i->to, sub::Time::from_hms (0, 2, 44, 150));
72         j = i->lines.begin();
73         BOOST_REQUIRE (j != i->lines.end ());
74         BOOST_REQUIRE_EQUAL (j->blocks.size(), 1);
75         b = j->blocks.front ();
76         BOOST_CHECK_EQUAL (b.text, "Toujours rien.");
77         BOOST_CHECK_EQUAL (b.font.get(), "Wolf_Rain");
78         BOOST_CHECK_CLOSE(b.font_size.proportional().get(), fs(56), 0.1);
79         BOOST_CHECK_EQUAL (b.bold, false);
80         BOOST_CHECK_EQUAL (b.italic, false);
81         BOOST_CHECK_EQUAL (b.underline, false);
82         ++i;
83
84         BOOST_CHECK (i == subs.end());
85 }
86
87
88 BOOST_AUTO_TEST_CASE (ssa_reader_line_test1)
89 {
90         sub::RawSubtitle base;
91         auto r = sub::SSAReader::parse_line (
92                 base,
93                 "This is a line with some {\\i1}italics{\\i0} and then\\nthere is a new line.",
94                 1920, 1080,
95                 sub::Colour(1, 1, 1)
96                 );
97
98         auto i = r.begin();
99         BOOST_CHECK_EQUAL (i->text, "This is a line with some ");
100         BOOST_CHECK_EQUAL (i->italic, false);
101         ++i;
102         BOOST_REQUIRE (i != r.end ());
103
104         BOOST_CHECK_EQUAL (i->text, "italics");
105         BOOST_CHECK_EQUAL (i->italic, true);
106         ++i;
107         BOOST_REQUIRE (i != r.end ());
108
109         BOOST_CHECK_EQUAL (i->text, " and then");
110         BOOST_CHECK_EQUAL (i->italic, false);
111         ++i;
112         BOOST_REQUIRE (i != r.end ());
113
114         BOOST_CHECK_EQUAL (i->text, "there is a new line.");
115         ++i;
116         BOOST_REQUIRE (i == r.end ());
117 }
118
119
120 BOOST_AUTO_TEST_CASE (ssa_reader_line_test2)
121 {
122         sub::RawSubtitle base;
123         auto r = sub::SSAReader::parse_line (
124                 base,
125                 "{\\i1}It's all just italics{\\i0}",
126                 1920, 1080,
127                 sub::Colour(1, 1, 1)
128                 );
129
130         /* Convert a font size in points to a vertical position for this file */
131         auto vp = [](int x) {
132                 return x * 1.2 / 1080;
133         };
134
135         auto i = r.begin ();
136         BOOST_CHECK_EQUAL (i->text, "It's all just italics");
137         BOOST_CHECK_EQUAL (i->italic, true);
138         ++i;
139         BOOST_REQUIRE (i == r.end ());
140
141         r = sub::SSAReader::parse_line (
142                 base,
143                 "{\\i1}Italic{\\i0}\\Nand new line",
144                 1920, 1080,
145                 sub::Colour(1, 1, 1)
146                 );
147
148         i = r.begin ();
149         BOOST_CHECK_EQUAL (i->text, "Italic");
150         BOOST_CHECK_EQUAL (i->italic, true);
151         BOOST_CHECK(fabs(vp(72) - i->vertical_position.proportional.get()) < 1e-5);
152         ++i;
153         BOOST_CHECK_EQUAL (i->text, "and new line");
154         BOOST_CHECK_EQUAL (i->italic, false);
155         BOOST_CHECK (i->vertical_position.proportional.get() < 1e-5);
156 }
157
158
159 static void
160 test (boost::filesystem::path p)
161 {
162         p = private_test / p;
163         FILE* f = fopen (p.string().c_str(), "r");
164         BOOST_REQUIRE (f);
165         sub::SSAReader r (f);
166         fclose (f);
167 }
168
169 /** Test of reading some typical .ssa files */
170 BOOST_AUTO_TEST_CASE (ssa_reader_test2)
171 {
172         test ("DKH_UT_EN20160601def.ssa");
173         test ("dcpsubtest-en.ssa");
174         test ("dcpsubtest-en.ssa");
175         test ("W_GERMAN_SUBS_grey.ass");
176 }
177
178 #define SUB_START(f, t) \
179         BOOST_REQUIRE (i != subs.end ()); \
180         BOOST_CHECK_EQUAL (i->from, f); \
181         BOOST_CHECK_EQUAL (i->to, t); \
182         j = i->lines.begin ();
183
184 #define LINE(vp, vr, hp, hr)                  \
185         BOOST_REQUIRE (j != i->lines.end ()); \
186         BOOST_CHECK (j->vertical_position.proportional); \
187         BOOST_CHECK (fabs (j->vertical_position.proportional.get() - vp) < 1e-5); \
188         BOOST_CHECK (j->vertical_position.reference); \
189         BOOST_CHECK_EQUAL (j->vertical_position.reference.get(), vr); \
190         BOOST_CHECK (fabs (j->horizontal_position.proportional - hp) < 1e-5); \
191         BOOST_CHECK_EQUAL (j->horizontal_position.reference, hr); \
192         k = j->blocks.begin (); \
193         ++j;
194
195 #define BLOCK(t, f, s, b, i, u) \
196         BOOST_REQUIRE (k != j->blocks.end ()); \
197         BOOST_CHECK_EQUAL (k->text, t); \
198         BOOST_CHECK_EQUAL (k->font.get(), f); \
199         BOOST_CHECK_CLOSE(k->font_size.proportional().get(), s, 0.1); \
200         BOOST_CHECK_EQUAL (k->bold, b); \
201         BOOST_CHECK_EQUAL (k->italic, i); \
202         BOOST_CHECK_EQUAL (k->underline, u); \
203         ++k;
204
205 #define SUB_END() \
206         ++i;
207
208 /** Test reading of a file within the libsub tree which exercises the parser */
209 BOOST_AUTO_TEST_CASE (ssa_reader_test3)
210 {
211         boost::filesystem::path p = "test/data/test.ssa";
212         FILE* f = fopen (p.string().c_str(), "r");
213         sub::SSAReader reader (f);
214         fclose (f);
215         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
216
217         /* Convert a font size in points to a proportional size for this file */
218         auto fs = [](int x) {
219                 return static_cast<float>(x) / 1080;
220         };
221
222         /* Convert a font size in points to a vertical position for this file */
223         auto vp = [&fs](int x) {
224                 return fs(x) * 1.2;
225         };
226
227         auto i = subs.begin();
228         vector<sub::Line>::iterator j;
229         vector<sub::Block>::iterator k;
230
231         /* Hello world */
232         SUB_START (sub::Time::from_hms (0, 0, 1, 230), sub::Time::from_hms (0, 0, 4, 550));
233         LINE((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
234         BLOCK("Hello world", "Arial", fs(20), false, false, false);
235         SUB_END();
236
237         /* This is vertically moved\nand has two lines. */
238         SUB_START (sub::Time::from_hms (0, 0, 5, 740), sub::Time::from_hms (0, 0, 11, 0));
239         /* The first line should be 900 pixels and one line (20
240            points, 1.2 times spaced, as a proportion of the total
241            screen height 729 points) up.
242         */
243         LINE((900.0 / 1080) - vp(20), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
244         BLOCK("This is vertically moved", "Arial", fs(20), false, false, false);
245         LINE((900.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
246         BLOCK("and has two lines.", "Arial", fs(20), false, false, false);
247         SUB_END();
248
249         /* Some {\i1}italics{\i} are here. */
250         SUB_START (sub::Time::from_hms (0, 0, 7, 740), sub::Time::from_hms (0, 0, 9, 0));
251         LINE((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
252         BLOCK("Some ", "Arial", fs(20), false, false, false);
253         BLOCK("italics", "Arial", fs(20), false, true, false);
254         BLOCK(" are here.", "Arial", fs(20), false, false, false);
255         SUB_END();
256
257         /* Alignments */
258
259         SUB_START (sub::Time::from_hms (0, 0, 9, 230), sub::Time::from_hms (0, 0, 11, 560));
260         LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
261         BLOCK("bottom left", "Arial", fs(20), false, false, false);
262         SUB_END ();
263
264         SUB_START (sub::Time::from_hms (0, 0, 9, 240), sub::Time::from_hms (0, 0, 11, 560));
265         LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
266         BLOCK("bottom centre", "Arial", fs(20), false, false, false);
267         SUB_END ();
268
269         SUB_START (sub::Time::from_hms (0, 0, 9, 250), sub::Time::from_hms (0, 0, 11, 560));
270         LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
271         BLOCK("bottom right", "Arial", fs(20), false, false, false);
272         SUB_END ();
273
274         SUB_START (sub::Time::from_hms (0, 0, 9, 260), sub::Time::from_hms (0, 0, 11, 560));
275         /* Position is half of a 20pt line (with line spacing) above vertical centre */
276         LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
277         BLOCK("middle left", "Arial", fs(20), false, false, false);
278         SUB_END ();
279
280         SUB_START (sub::Time::from_hms (0, 0, 9, 270), sub::Time::from_hms (0, 0, 11, 560));
281         LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
282         BLOCK("middle centre", "Arial", fs(20), false, false, false);
283         SUB_END ();
284
285         SUB_START (sub::Time::from_hms (0, 0, 9, 280), sub::Time::from_hms (0, 0, 11, 560));
286         LINE (-vp(10), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
287         BLOCK("middle right", "Arial", fs(20), false, false, false);
288         SUB_END ();
289
290         SUB_START (sub::Time::from_hms (0, 0, 9, 290), sub::Time::from_hms (0, 0, 11, 560));
291         LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::LEFT_OF_SCREEN);
292         BLOCK("top left", "Arial", fs(20), false, false, false);
293         SUB_END ();
294
295         SUB_START (sub::Time::from_hms (0, 0, 9, 300), sub::Time::from_hms (0, 0, 11, 560));
296         LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
297         BLOCK("top centre", "Arial", fs(20), false, false, false);
298         SUB_END ();
299
300         SUB_START (sub::Time::from_hms (0, 0, 9, 310), sub::Time::from_hms (0, 0, 11, 560));
301         LINE ((10.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::RIGHT_OF_SCREEN);
302         BLOCK("top right", "Arial", fs(20), false, false, false);
303         SUB_END ();
304
305         BOOST_REQUIRE (i == subs.end ());
306 }
307
308
309 /** Test reading of a file within the libsub-test-private tree which exercises the parser */
310 BOOST_AUTO_TEST_CASE (ssa_reader_test4)
311 {
312         boost::filesystem::path p = private_test / "dcpsubtest2-en.ssa";
313         FILE* f = fopen (p.string().c_str(), "r");
314         sub::SSAReader reader (f);
315         fclose (f);
316         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
317
318         auto i = subs.begin();
319         vector<sub::Line>::iterator j;
320         vector<sub::Block>::iterator k;
321
322         BOOST_REQUIRE (i != subs.end ());
323
324         /* Convert a font size in points to a proportional size for this file */
325         auto fs = [](int x) {
326                 return static_cast<float>(x) / 288;
327         };
328
329         /* Convert a font size in points to a vertical position for this file */
330         auto vp = [&fs](int x) {
331                 return fs(x) * 1.2;
332         };
333
334         SUB_START (sub::Time::from_hms (0, 0, 1, 0), sub::Time::from_hms (0, 0, 3, 0));
335         /* The first line should be one line (50 points, 1.2 times
336            spaced, as a proportion of the total screen height 729
337            points) up.
338         */
339         LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
340         BLOCK("1st line: This is normal", "Verdana", fs(50), false, false, false);
341         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
342         BLOCK("2d line: this is bold", "Verdana", fs(50), true, false, false);
343         SUB_END ();
344
345         SUB_START (sub::Time::from_hms (0, 0, 3, 100), sub::Time::from_hms (0, 0, 5, 100));
346         LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
347         BLOCK("1st line: this is bold", "Verdana", fs(50), true, false, false);
348         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
349         BLOCK("2nd line: This is normal", "Verdana", fs(50), false, false, false);
350         SUB_END ();
351
352         SUB_START (sub::Time::from_hms (0, 0, 5, 200), sub::Time::from_hms (0, 0, 7, 200));
353         LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
354         BLOCK("1st line: this is bold", "Verdana", fs(50), true, false, false);
355         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
356         BLOCK("2nd line: this is italics", "Verdana", fs(50), false, true, false);
357         SUB_END ();
358
359         SUB_START (sub::Time::from_hms (0, 0, 7, 300), sub::Time::from_hms (0, 0, 9, 300));
360         LINE(vp(50), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
361         BLOCK("1st line: this is italics", "Verdana", fs(50), false, true, false);
362         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
363         BLOCK("2nd line: this is bold", "Verdana", fs(50), true, false, false);
364         SUB_END ();
365 }
366
367
368 /** Test reading of a .ass file */
369 BOOST_AUTO_TEST_CASE (ssa_reader_test5)
370 {
371         boost::filesystem::path p = private_test / "dcpsubtest-en.ass";
372         FILE* f = fopen (p.string().c_str(), "r");
373         sub::SSAReader reader (f);
374         fclose (f);
375         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
376
377         /* Convert a font size in points to a proportional size for this file */
378         auto fs = [](int x) {
379                 return static_cast<float>(x) / 288;
380         };
381
382         /* Convert a font size in points to a vertical position for this file */
383         auto vp = [&fs](int x) {
384                 return fs(x) * 1.2;
385         };
386
387         auto i = subs.begin ();
388         vector<sub::Line>::iterator j;
389         vector<sub::Block>::iterator k;
390
391         BOOST_REQUIRE (i != subs.end ());
392
393         SUB_START (sub::Time::from_hms (0, 0, 1, 0), sub::Time::from_hms (0, 0, 3, 0));
394         /* The first line should be one line (26 points, 1.2 times
395            spaced, as a proportion of the total screen height 729
396            points) up.
397         */
398         LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
399         BLOCK("1st subtitle, 1st line", "arial", fs(26), true, false, false);
400         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
401         BLOCK("2nd subtitle, 2nd line", "arial", fs(26), true, false, false);
402         SUB_END ();
403
404         SUB_START (sub::Time::from_hms (0, 0, 3, 100), sub::Time::from_hms (0, 0, 5, 100));
405         LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
406         BLOCK("2nd subtitle, 1st line", "arial", fs(26), true, false, false);
407         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
408         BLOCK("2nd subtitle, 2nd line", "arial", fs(26), true, false, false);
409         SUB_END ();
410
411         SUB_START (sub::Time::from_hms (0, 0, 5, 200), sub::Time::from_hms (0, 0, 7, 200));
412         LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
413         BLOCK("3rd subtitle, 1st line", "arial", fs(26), true, false, false);
414         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
415         BLOCK("3rd subtitle, 2nd line", "arial", fs(26), true, false, false);
416         SUB_END ();
417
418         SUB_START (sub::Time::from_hms (0, 0, 7, 300), sub::Time::from_hms (0, 0, 9, 300));
419         LINE(vp(26), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
420         BLOCK("4th subtitle, 1st line", "arial", fs(26), true, false, false);
421         LINE(0, sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
422         BLOCK("4th subtitle, 2nd line", "arial", fs(26), true, false, false);
423         SUB_END ();
424 }
425
426
427 /** Test reading of another .ass file */
428 BOOST_AUTO_TEST_CASE (ssa_reader_test6)
429 {
430         boost::filesystem::path p = private_test / "DCP-o-matic_test_subs_1.ass";
431         auto f = fopen (p.string().c_str(), "r");
432         BOOST_REQUIRE (f);
433         sub::SSAReader reader (f);
434         fclose (f);
435         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
436
437         /* Convert a font size in points to a proportional size for this file */
438         auto fs = [](int x) {
439                 return static_cast<float>(x) / 288;
440         };
441
442         /* Convert a font size in points to a vertical position for this file */
443         auto vp = [&fs](int x) {
444                 return fs(x) * 1.2;
445         };
446
447         auto i = subs.begin ();
448         vector<sub::Line>::iterator j;
449         vector<sub::Block>::iterator k;
450
451         BOOST_REQUIRE (i != subs.end ());
452
453         SUB_START (sub::Time::from_hms (0, 0, 0, 70), sub::Time::from_hms (0, 0, 1, 110));
454         /* The first line should be one line (30 points, 1.2 times
455            spaced, as a proportion of the total screen height 792
456            points) up.  There's also a 10 pixel (with respect to a
457            288-pixel-high screen) margin.
458         */
459         LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
460         BLOCK("This line is normal", "Arial", fs(30), false, false, false);
461         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
462         BLOCK("This line is bold", "Arial", fs(30), true, false, false);
463         SUB_END ();
464
465         SUB_START (sub::Time::from_hms (0, 0, 1, 200), sub::Time::from_hms (0, 0, 2, 240));
466         LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
467         BLOCK("This line is bold", "Arial", fs(30), true, false, false);
468         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
469         BLOCK("This line is normal", "Arial", fs(30), false, false, false);
470         SUB_END ();
471
472         SUB_START (sub::Time::from_hms (0, 0, 2, 300), sub::Time::from_hms (0, 0, 3, 380));
473         LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
474         BLOCK("This line is bold", "Arial", fs(30), true, false, false);
475         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
476         BLOCK("This line is italic", "Arial", fs(30), false, true, false);
477         SUB_END ();
478
479         SUB_START (sub::Time::from_hms (0, 0, 3, 400), sub::Time::from_hms (0, 0, 4, 480));
480         LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
481         BLOCK("This line is italic", "Arial", fs(30), false, true, false);
482         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
483         BLOCK("This line is bold", "Arial", fs(30), true, false, false);
484         SUB_END ();
485
486         SUB_START (sub::Time::from_hms (0, 0, 4, 510), sub::Time::from_hms (0, 0, 5, 600));
487         LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
488         BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
489         BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
490         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
491         BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
492         BLOCK("italic AND bold", "Arial", fs(30), true, true, false);
493         SUB_END ();
494
495         SUB_START (sub::Time::from_hms (0, 0, 5, 620), sub::Time::from_hms (0, 0, 6, 710));
496         LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
497         BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
498         BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
499         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
500         BLOCK("First three words", "Arial", fs(30), true, true, false);
501         BLOCK(" are italic AND bold", "Arial", fs(30), false, false, false);
502         SUB_END ();
503
504         SUB_START (sub::Time::from_hms (0, 0, 6, 730), sub::Time::from_hms (0, 0, 8, 30));
505         LINE ((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
506         BLOCK("Last three words are ", "Arial", fs(30), false, false, false);
507         BLOCK("bold AND italic", "Arial", fs(30), true, true, false);
508         LINE ((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
509         BLOCK("This line is normal", "Arial", fs(30), false, false, false);
510         SUB_END ();
511
512         SUB_START (sub::Time::from_hms (0, 0, 8, 90), sub::Time::from_hms (0, 0, 9, 210));
513         LINE((vp(30) + (10.0 / 288.0)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
514         BLOCK("Both lines are bold AND italic", "Arial", fs(30), true, true, false);
515         LINE((10.0 / 288.0), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
516         BLOCK("Both lines are bold AND italic", "Arial", fs(30), true, true, false);
517         SUB_END ();
518 }
519
520
521 BOOST_AUTO_TEST_CASE (ssa_reader_test7)
522 {
523         auto p = boost::filesystem::path("test") / "data" / "test3.ssa";
524         auto f = fopen(p.string().c_str(), "r");
525         BOOST_REQUIRE(f);
526         sub::SSAReader reader(f);
527         fclose(f);
528         auto subs = sub::collect<vector<sub::Subtitle>>(reader.subtitles());
529
530         /* Convert a font size in points to a proportional size for this file */
531         auto fs = [](int x) {
532                 return static_cast<float>(x) / 1080;
533         };
534
535         /* Convert a font size in points to a vertical position for this file */
536         auto vp = [&fs](int x) {
537                 return fs(x) * 1.2;
538         };
539
540         auto i = subs.begin();
541         vector<sub::Line>::iterator j;
542         vector<sub::Block>::iterator k;
543
544         BOOST_REQUIRE (i != subs.end());
545
546         SUB_START(sub::Time::from_hms(0, 0, 1, 0), sub::Time::from_hms(0, 0, 3, 0));
547         LINE((vp(60) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
548         BLOCK("Helvetica Neue 60pt - Default", "Helvetica Neue", fs(60), false, false, false);
549         LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
550         BLOCK("Bottom 100 pt off edge", "Helvetica Neue", fs(60), false, false, false);
551         SUB_END();
552
553         SUB_START(sub::Time::from_hms(0, 0, 4, 0), sub::Time::from_hms(0, 0, 6, 0));
554         LINE((vp(30) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
555         BLOCK("Helvetica Neue 30pt", "Helvetica Neue", fs(30), false, false, false);
556         LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
557         BLOCK("Bottom 100pt off edge", "Helvetica Neue", fs(30), false, false, false);
558         SUB_END();
559
560         SUB_START(sub::Time::from_hms(0, 0, 7, 0), sub::Time::from_hms(0, 0, 9, 0));
561         LINE((vp(120) + (100.0 / 1080)), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
562         BLOCK("Helvetica Neue 120pt", "Helvetica Neue", fs(120), false, false, false);
563         LINE((100.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
564         BLOCK("Bottom 100pt off edge", "Helvetica Neue", fs(120), false, false, false);
565         SUB_END();
566
567         SUB_START(sub::Time::from_hms(0, 0, 10, 0), sub::Time::from_hms(0, 0, 12, 0));
568         LINE((100.0 / 1080), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
569         BLOCK("Helvetica Neue 60pt", "Helvetica Neue", fs(60), false, false, false);
570         LINE((vp(60) + (100.0 / 1080)), sub::TOP_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
571         BLOCK("Top Alignment 100pt off edge", "Helvetica Neue", fs(60), false, false, false);
572         SUB_END();
573
574         SUB_START(sub::Time::from_hms(0, 0, 13, 0), sub::Time::from_hms(0, 0, 15, 0));
575         LINE(vp(-60), sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
576         BLOCK("Helvetica Neue 60pt", "Helvetica Neue 60 Center", fs(60), false, false, false);
577         LINE(0, sub::VERTICAL_CENTRE_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
578         BLOCK(" Vertical Center Alignment", "Helvetica Neue 60 Center", fs(60), false, false, false);
579         SUB_END();
580 }
581
582
583 /** Test \pos */
584 BOOST_AUTO_TEST_CASE (ssa_reader_pos)
585 {
586         boost::filesystem::path p = "test/data/test2.ssa";
587         FILE* f = fopen (p.string().c_str(), "r");
588         sub::SSAReader reader (f);
589         fclose (f);
590         auto subs = sub::collect<vector<sub::Subtitle>> (reader.subtitles());
591
592         /* Convert a font size in points to a proportional size for this file */
593         auto fs = [](int x) {
594                 return static_cast<float>(x) / 1080;
595         };
596
597         auto i = subs.begin ();
598         vector<sub::Line>::iterator j;
599         vector<sub::Block>::iterator k;
600
601         /* Hello world */
602         SUB_START (sub::Time::from_hms (0, 0, 1, 230), sub::Time::from_hms (0, 0, 4, 550));
603         LINE ((10.0 / 1080), sub::BOTTOM_OF_SCREEN, 0, sub::HORIZONTAL_CENTRE_OF_SCREEN);
604         BLOCK ("Hello world this is ", "Arial", fs(20), false, false, false);
605         LINE ((310.0 / 1080), sub::TOP_OF_SCREEN, 400.0 / 1920, sub::LEFT_OF_SCREEN);
606         BLOCK ("positioning.", "Arial", fs(20), false, false, false);
607         SUB_END();
608 }
609
610
611 /** Test \fs */
612 BOOST_AUTO_TEST_CASE (ssa_reader_fs)
613 {
614         sub::RawSubtitle base;
615         auto r = sub::SSAReader::parse_line (
616                 base,
617                 "This is a line with some {\\fs64}font sizing.",
618                 1920, 1080,
619                 sub::Colour(1, 1, 1)
620                 );
621
622         auto i = r.begin ();
623         BOOST_CHECK_EQUAL (i->text, "This is a line with some ");
624         ++i;
625         BOOST_REQUIRE (i != r.end ());
626
627         BOOST_CHECK_EQUAL (i->text, "font sizing.");
628         BOOST_REQUIRE(i->font_size.proportional());
629         BOOST_CHECK_CLOSE(i->font_size.proportional().get(), 64.0 / 1080, 0.1);
630         ++i;
631         BOOST_REQUIRE (i == r.end ());
632 }
633
634
635 static void
636 test_c(string command, string colour)
637 {
638         sub::RawSubtitle base;
639         auto r = sub::SSAReader::parse_line (
640                 base,
641                 String::compose("{\\c%1}Hello world", command),
642                 1920, 1080,
643                 sub::Colour(1, 0, 1)
644                 );
645
646         auto i = r.begin ();
647         BOOST_CHECK_EQUAL (i->text, "Hello world");
648         BOOST_CHECK (i->colour == sub::Colour::from_rgb_hex(colour));
649         BOOST_REQUIRE(std::next(i) == r.end());
650 }
651
652
653 /** Test a valid \c */
654 BOOST_AUTO_TEST_CASE (ssa_reader_c)
655 {
656         test_c("&H00FFFF&", "ffff00");
657         test_c("&H123456&", "563412");
658         test_c("&H0&", "000000");
659         test_c("&HFF&", "ff0000");
660         test_c("&HFF00&", "00ff00");
661         test_c("&HFF0000&", "0000ff");
662         test_c("&HFFFFFF&", "ffffff");
663         /* \c with no parameter seems to be parsed as "return to primary colour" */
664         test_c("", "ff00ff");
665 }
666