Write subtitle files in binary mode.
[libdcp.git] / test / smpte_subtitle_test.cc
1 /*
2     Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
6     libdcp is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     libdcp is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34
35 #include "smpte_load_font_node.h"
36 #include "smpte_subtitle_asset.h"
37 #include "stream_operators.h"
38 #include "subtitle_image.h"
39 #include "test.h"
40 #include "types.h"
41 #include <boost/optional/optional_io.hpp>
42 #include <boost/test/unit_test.hpp>
43
44
45 using std::make_shared;
46 using std::string;
47 using std::shared_ptr;
48 using std::dynamic_pointer_cast;
49 using std::vector;
50 using boost::optional;
51
52
53 BOOST_AUTO_TEST_CASE (smpte_subtitle_id_test)
54 {
55         dcp::SMPTESubtitleAsset subs;
56         subs.add(
57                 make_shared<dcp::SubtitleString>(
58                         optional<string>(),
59                         false, false, false,
60                         dcp::Colour(),
61                         64,
62                         1,
63                         dcp::Time(0, 1, 2, 3, 24),
64                         dcp::Time(0, 2, 2, 3, 24),
65                         0.5,
66                         dcp::HAlign::CENTER,
67                         0.5,
68                         dcp::VAlign::CENTER,
69                         dcp::Direction::LTR,
70                         "Hello",
71                         dcp::Effect::NONE,
72                         dcp::Colour(),
73                         dcp::Time(0, 0, 0, 0, 24),
74                         dcp::Time(0, 0, 0, 0, 24),
75                         0
76                         )
77                 );
78         subs.write("build/test/smpte_subtitle_id_test.mxf");
79
80         dcp::SMPTESubtitleAsset check("build/test/smpte_subtitle_id_test.mxf");
81         BOOST_CHECK(check.id() != check.xml_id());
82 }
83
84
85 /** Check reading of a SMPTE subtitle file */
86 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test)
87 {
88         dcp::SMPTESubtitleAsset sc (
89                 private_test /
90                 "data" /
91                 "JourneyToJah_TLR-1_F_EN-DE-FR_CH_51_2K_LOK_20140225_DGL_SMPTE_OV" /
92                 "8b48f6ae-c74b-4b80-b994-a8236bbbad74_sub.mxf"
93                 );
94
95         BOOST_CHECK_EQUAL (sc.id(), "8b48f6ae-c74b-4b80-b994-a8236bbbad74");
96         BOOST_CHECK_EQUAL (sc.content_title_text(), "Journey to Jah");
97         BOOST_REQUIRE (sc.annotation_text());
98         BOOST_CHECK_EQUAL (sc.annotation_text().get(), "Journey to Jah");
99         BOOST_CHECK_EQUAL (sc.issue_date(), dcp::LocalTime ("2014-02-25T11:22:48.000-00:00"));
100         BOOST_REQUIRE (sc.reel_number());
101         BOOST_CHECK_EQUAL (sc.reel_number().get(), 1);
102         BOOST_REQUIRE (sc.language ());
103         BOOST_CHECK_EQUAL (sc.language().get (), "de");
104         BOOST_CHECK_EQUAL (sc.edit_rate(), dcp::Fraction (25, 1));
105         BOOST_CHECK_EQUAL (sc.time_code_rate(), 25);
106         BOOST_CHECK_EQUAL (sc.start_time(), dcp::Time (0, 0, 0, 0, 25));
107         auto lfn = sc.load_font_nodes ();
108         BOOST_REQUIRE_EQUAL (lfn.size(), 1U);
109         shared_ptr<dcp::SMPTELoadFontNode> smpte_lfn = dynamic_pointer_cast<dcp::SMPTELoadFontNode> (lfn.front ());
110         BOOST_REQUIRE (smpte_lfn);
111         BOOST_CHECK_EQUAL (smpte_lfn->id, "theFontId");
112         BOOST_CHECK_EQUAL (smpte_lfn->urn, "9118bbce-4105-4a05-b37c-a5a6f75e1fea");
113         BOOST_REQUIRE_EQUAL (sc.subtitles().size(), 63U);
114         BOOST_REQUIRE (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front()));
115         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front())->text(), "Noch mal.");
116         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().front())->space_before(), 0.0f);
117         BOOST_CHECK_EQUAL (sc.subtitles().front()->in(), dcp::Time (0, 0, 25, 12, 25));
118         BOOST_CHECK_EQUAL (sc.subtitles().front()->out(), dcp::Time (0, 0, 26, 4, 25));
119         BOOST_REQUIRE (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back()));
120         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back())->text(), "Prochainement");
121         BOOST_CHECK_EQUAL (dynamic_pointer_cast<const dcp::SubtitleString>(sc.subtitles().back())->space_before(), 0.0f);
122         BOOST_CHECK_EQUAL (sc.subtitles().back()->in(), dcp::Time (0, 1, 57, 17, 25));
123         BOOST_CHECK_EQUAL (sc.subtitles().back()->out(), dcp::Time (0, 1, 58, 12, 25));
124 }
125
126
127 /** And another one featuring <Font> within <Text> and some <Space> */
128 BOOST_AUTO_TEST_CASE (read_smpte_subtitle_test2)
129 {
130         dcp::SMPTESubtitleAsset sc (private_test / "olsson.xml");
131
132         auto subs = sc.subtitles();
133         BOOST_REQUIRE_EQUAL (subs.size(), 6U);
134         auto i = 0;
135         auto is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
136         BOOST_REQUIRE (is);
137         BOOST_CHECK_EQUAL (is->text(), "Testing is ");
138         BOOST_CHECK (!is->italic());
139         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
140         ++i;
141         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
142         BOOST_REQUIRE (is);
143         BOOST_CHECK_EQUAL (is->text(), "really");
144         BOOST_CHECK (is->italic());
145         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
146         ++i;
147         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
148         BOOST_REQUIRE (is);
149         BOOST_CHECK_EQUAL (is->text(), " fun!");
150         BOOST_CHECK (!is->italic());
151         BOOST_CHECK_CLOSE (is->space_before(), 5, 0.1);
152         ++i;
153         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
154         BOOST_REQUIRE (is);
155         BOOST_CHECK_EQUAL (is->text(), "This is the ");
156         BOOST_CHECK (!is->italic());
157         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
158         ++i;
159         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
160         BOOST_REQUIRE (is);
161         BOOST_CHECK_EQUAL (is->text(), "second");
162         BOOST_CHECK (is->italic());
163         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
164         ++i;
165         is = dynamic_pointer_cast<const dcp::SubtitleString>(subs[i]);
166         BOOST_REQUIRE (is);
167         BOOST_CHECK_EQUAL (is->text(), " line!");
168         BOOST_CHECK (!is->italic());
169         BOOST_CHECK_CLOSE (is->space_before(), 0, 0.1);
170 }
171
172
173 /* Write some subtitle content as SMPTE XML and check that it is right */
174 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test)
175 {
176         dcp::SMPTESubtitleAsset c;
177         c.set_reel_number (1);
178         c.set_language (dcp::LanguageTag("en"));
179         c.set_content_title_text ("Test");
180         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
181
182         c.add (
183                 make_shared<dcp::SubtitleString> (
184                         string ("Frutiger"),
185                         false,
186                         false,
187                         false,
188                         dcp::Colour (255, 255, 255),
189                         48,
190                         1.0,
191                         dcp::Time (0, 4,  9, 22, 24),
192                         dcp::Time (0, 4, 11, 22, 24),
193                         0,
194                         dcp::HAlign::CENTER,
195                         0.8,
196                         dcp::VAlign::TOP,
197                         dcp::Direction::LTR,
198                         "Hello world",
199                         dcp::Effect::NONE,
200                         dcp::Colour (0, 0, 0),
201                         dcp::Time (0, 0, 0, 0, 24),
202                         dcp::Time (0, 0, 0, 0, 24),
203                         0
204                         )
205                 );
206
207         c.add (
208                 make_shared<dcp::SubtitleString>(
209                         boost::optional<string> (),
210                         true,
211                         true,
212                         true,
213                         dcp::Colour (128, 0, 64),
214                         91,
215                         1.0,
216                         dcp::Time (5, 41,  0, 21, 24),
217                         dcp::Time (6, 12, 15, 21, 24),
218                         0,
219                         dcp::HAlign::CENTER,
220                         0.4,
221                         dcp::VAlign::BOTTOM,
222                         dcp::Direction::RTL,
223                         "What's going ",
224                         dcp::Effect::BORDER,
225                         dcp::Colour (1, 2, 3),
226                         dcp::Time (1, 2, 3, 4, 24),
227                         dcp::Time (5, 6, 7, 8, 24),
228                         0
229                         )
230                 );
231
232         c.add (
233                 make_shared<dcp::SubtitleString>(
234                         boost::optional<string> (),
235                         true,
236                         true,
237                         true,
238                         dcp::Colour (128, 0, 64),
239                         91,
240                         1.0,
241                         dcp::Time (5, 41,  0, 21, 24),
242                         dcp::Time (6, 12, 15, 21, 24),
243                         0,
244                         dcp::HAlign::CENTER,
245                         0.4,
246                         dcp::VAlign::BOTTOM,
247                         dcp::Direction::RTL,
248                         "on",
249                         dcp::Effect::BORDER,
250                         dcp::Colour (1, 2, 3),
251                         dcp::Time (1, 2, 3, 4, 24),
252                         dcp::Time (5, 6, 7, 8, 24),
253                         4.2
254                         )
255                 );
256
257         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
258
259         check_xml (
260                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
261                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
262                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
263                 "  <ContentTitleText>Test</ContentTitleText>\n"
264                 "  <IssueDate>2016-04-01T03:52:00.000+00:00</IssueDate>\n"
265                 "  <ReelNumber>1</ReelNumber>\n"
266                 "  <Language>en</Language>\n"
267                 "  <EditRate>24 1</EditRate>\n"
268                 "  <TimeCodeRate>24</TimeCodeRate>\n"
269                 "  <SubtitleList>\n"
270                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Frutiger\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
271                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:04:09:22\" TimeOut=\"00:04:11:22\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
272                 "        <Text Valign=\"top\" Vposition=\"80\">Hello world</Text>\n"
273                 "      </Subtitle>\n"
274                 "    </Font>\n"
275                 "    <Font AspectAdjust=\"1.0\" Color=\"FF800040\" Effect=\"border\" EffectColor=\"FF010203\" Italic=\"yes\" Script=\"normal\" Size=\"91\" Underline=\"yes\" Weight=\"bold\">\n"
276                 "      <Subtitle SpotNumber=\"2\" TimeIn=\"05:41:00:21\" TimeOut=\"06:12:15:21\" FadeUpTime=\"01:02:03:04\" FadeDownTime=\"05:06:07:08\">\n"
277                 "        <Text Valign=\"bottom\" Vposition=\"40\" Direction=\"rtl\">What's going <Space Size=\"4.2\"/>on</Text>\n"
278                 "      </Subtitle>\n"
279                 "    </Font>\n"
280                 "  </SubtitleList>\n"
281                 "</SubtitleReel>",
282                 c.xml_as_string (),
283                 vector<string>()
284                 );
285 }
286
287 /* Write some subtitle content as SMPTE XML and check that it is right.
288    This includes in-line font changes.
289 */
290 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test2)
291 {
292         dcp::SMPTESubtitleAsset c;
293         c.set_reel_number (1);
294         c.set_language (dcp::LanguageTag("en"));
295         c.set_content_title_text ("Test");
296         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
297
298         c.add (
299                 make_shared<dcp::SubtitleString>(
300                         string ("Arial"),
301                         false,
302                         false,
303                         false,
304                         dcp::Colour (255, 255, 255),
305                         48,
306                         1.0,
307                         dcp::Time (0, 0, 1, 0, 24),
308                         dcp::Time (0, 0, 9, 0, 24),
309                         0,
310                         dcp::HAlign::CENTER,
311                         0.8,
312                         dcp::VAlign::TOP,
313                         dcp::Direction::LTR,
314                         "Testing is ",
315                         dcp::Effect::NONE,
316                         dcp::Colour (0, 0, 0),
317                         dcp::Time (0, 0, 0, 0, 24),
318                         dcp::Time (0, 0, 0, 0, 24),
319                         0
320                         )
321                 );
322
323         c.add (
324                 make_shared<dcp::SubtitleString>(
325                         string ("Arial"),
326                         true,
327                         false,
328                         false,
329                         dcp::Colour (255, 255, 255),
330                         48,
331                         1.0,
332                         dcp::Time (0, 0, 1, 0, 24),
333                         dcp::Time (0, 0, 9, 0, 24),
334                         0,
335                         dcp::HAlign::CENTER,
336                         0.8,
337                         dcp::VAlign::TOP,
338                         dcp::Direction::LTR,
339                         "really",
340                         dcp::Effect::NONE,
341                         dcp::Colour (0, 0, 0),
342                         dcp::Time (0, 0, 0, 0, 24),
343                         dcp::Time (0, 0, 0, 0, 24),
344                         0
345                         )
346                 );
347
348         c.add (
349                 make_shared<dcp::SubtitleString>(
350                         string ("Arial"),
351                         false,
352                         false,
353                         false,
354                         dcp::Colour (255, 255, 255),
355                         48,
356                         1.0,
357                         dcp::Time (0, 0, 1, 0, 24),
358                         dcp::Time (0, 0, 9, 0, 24),
359                         0,
360                         dcp::HAlign::CENTER,
361                         0.8,
362                         dcp::VAlign::TOP,
363                         dcp::Direction::LTR,
364                         " fun",
365                         dcp::Effect::NONE,
366                         dcp::Colour (0, 0, 0),
367                         dcp::Time (0, 0, 0, 0, 24),
368                         dcp::Time (0, 0, 0, 0, 24),
369                         0
370                         )
371                 );
372
373         c.add (
374                 make_shared<dcp::SubtitleString>(
375                         string ("Arial"),
376                         false,
377                         false,
378                         false,
379                         dcp::Colour (255, 255, 255),
380                         48,
381                         1.0,
382                         dcp::Time (0, 0, 1, 0, 24),
383                         dcp::Time (0, 0, 9, 0, 24),
384                         0,
385                         dcp::HAlign::CENTER,
386                         0.9,
387                         dcp::VAlign::TOP,
388                         dcp::Direction::LTR,
389                         "This is the ",
390                         dcp::Effect::NONE,
391                         dcp::Colour (0, 0, 0),
392                         dcp::Time (0, 0, 0, 0, 24),
393                         dcp::Time (0, 0, 0, 0, 24),
394                         0
395                         )
396                 );
397
398         c.add (
399                 make_shared<dcp::SubtitleString>(
400                         string ("Arial"),
401                         true,
402                         false,
403                         false,
404                         dcp::Colour (255, 255, 255),
405                         48,
406                         1.0,
407                         dcp::Time (0, 0, 1, 0, 24),
408                         dcp::Time (0, 0, 9, 0, 24),
409                         0,
410                         dcp::HAlign::CENTER,
411                         0.9,
412                         dcp::VAlign::TOP,
413                         dcp::Direction::LTR,
414                         "second",
415                         dcp::Effect::NONE,
416                         dcp::Colour (0, 0, 0),
417                         dcp::Time (0, 0, 0, 0, 24),
418                         dcp::Time (0, 0, 0, 0, 24),
419                         0
420                         )
421                 );
422
423         c.add (
424                 make_shared<dcp::SubtitleString>(
425                         string ("Arial"),
426                         false,
427                         false,
428                         false,
429                         dcp::Colour (255, 255, 255),
430                         48,
431                         1.0,
432                         dcp::Time (0, 0, 1, 0, 24),
433                         dcp::Time (0, 0, 9, 0, 24),
434                         0,
435                         dcp::HAlign::CENTER,
436                         0.9,
437                         dcp::VAlign::TOP,
438                         dcp::Direction::LTR,
439                         " line",
440                         dcp::Effect::NONE,
441                         dcp::Colour (0, 0, 0),
442                         dcp::Time (0, 0, 0, 0, 24),
443                         dcp::Time (0, 0, 0, 0, 24),
444                         0
445                         )
446                 );
447
448         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
449
450         check_xml (
451                 c.xml_as_string(),
452                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
453                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
454                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
455                 "  <ContentTitleText>Test</ContentTitleText>\n"
456                 "  <IssueDate>2016-04-01T03:52:00.000+00:00</IssueDate>\n"
457                 "  <ReelNumber>1</ReelNumber>\n"
458                 "  <Language>en</Language>\n"
459                 "  <EditRate>24 1</EditRate>\n"
460                 "  <TimeCodeRate>24</TimeCodeRate>\n"
461                 "  <SubtitleList>\n"
462                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
463                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
464                 "        <Text Valign=\"top\" Vposition=\"80\"><Font Italic=\"no\">Testing is </Font><Font Italic=\"yes\">really</Font><Font Italic=\"no\"> fun</Font></Text>\n"
465                 "        <Text Valign=\"top\" Vposition=\"90\"><Font Italic=\"no\">This is the </Font><Font Italic=\"yes\">second</Font><Font Italic=\"no\"> line</Font></Text>\n"
466                 "      </Subtitle>\n"
467                 "    </Font>\n"
468                 "  </SubtitleList>\n"
469                 "</SubtitleReel>",
470                 vector<string>()
471                 );
472 }
473
474 /* Write some subtitle content as SMPTE using bitmaps and check that it is right */
475 BOOST_AUTO_TEST_CASE (write_smpte_subtitle_test3)
476 {
477         dcp::SMPTESubtitleAsset c;
478         c.set_reel_number (1);
479         c.set_language (dcp::LanguageTag("en"));
480         c.set_content_title_text ("Test");
481         c.set_start_time (dcp::Time());
482
483         boost::filesystem::path const sub_image = "test/data/sub.png";
484
485         c.add (
486                 make_shared<dcp::SubtitleImage>(
487                         dcp::ArrayData(sub_image),
488                         dcp::Time (0, 4,  9, 22, 24),
489                         dcp::Time (0, 4, 11, 22, 24),
490                         0,
491                         dcp::HAlign::CENTER,
492                         0.8,
493                         dcp::VAlign::TOP,
494                         dcp::Time (0, 0, 0, 0, 24),
495                         dcp::Time (0, 0, 0, 0, 24)
496                         )
497               );
498
499         c._id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
500
501         boost::filesystem::path path = "build/test/write_smpte_subtitle_test3";
502         boost::filesystem::create_directories (path);
503         c.write (path / "subs.mxf");
504
505         dcp::SMPTESubtitleAsset read_back (path / "subs.mxf");
506         auto subs = read_back.subtitles ();
507         BOOST_REQUIRE_EQUAL (subs.size(), 1U);
508         auto image = dynamic_pointer_cast<const dcp::SubtitleImage>(subs[0]);
509         BOOST_REQUIRE (image);
510
511         BOOST_CHECK (image->png_image() == dcp::ArrayData(sub_image));
512         BOOST_CHECK (image->in() == dcp::Time(0, 4, 9, 22, 24));
513         BOOST_CHECK (image->out() == dcp::Time(0, 4, 11, 22, 24));
514         BOOST_CHECK_CLOSE (image->h_position(), 0.0, 1);
515         BOOST_CHECK (image->h_align() == dcp::HAlign::CENTER);
516         BOOST_CHECK_CLOSE (image->v_position(), 0.8, 1);
517         BOOST_CHECK (image->v_align() == dcp::VAlign::TOP);
518         BOOST_CHECK (image->fade_up_time() == dcp::Time(0, 0, 0, 0, 24));
519         BOOST_CHECK (image->fade_down_time() == dcp::Time(0, 0, 0, 0, 24));
520 }
521
522
523 /* Some closed caption systems require the <Text> elements to be written in order of their
524  * vertical position (see DoM bug #2106).
525  */
526 BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_top_alignment)
527 {
528         dcp::SMPTESubtitleAsset c;
529         c.set_reel_number (1);
530         c.set_language (dcp::LanguageTag("en"));
531         c.set_content_title_text ("Test");
532         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
533
534         c.add (
535                 make_shared<dcp::SubtitleString>(
536                         string ("Arial"),
537                         false,
538                         false,
539                         false,
540                         dcp::Colour (255, 255, 255),
541                         48,
542                         1.0,
543                         dcp::Time (0, 0, 1, 0, 24),
544                         dcp::Time (0, 0, 9, 0, 24),
545                         0,
546                         dcp::HAlign::CENTER,
547                         0.8,
548                         dcp::VAlign::TOP,
549                         dcp::Direction::LTR,
550                         "Top line",
551                         dcp::Effect::NONE,
552                         dcp::Colour (0, 0, 0),
553                         dcp::Time (0, 0, 0, 0, 24),
554                         dcp::Time (0, 0, 0, 0, 24),
555                         0
556                         )
557                 );
558
559         c.add (
560                 make_shared<dcp::SubtitleString>(
561                         string ("Arial"),
562                         false,
563                         false,
564                         false,
565                         dcp::Colour (255, 255, 255),
566                         48,
567                         1.0,
568                         dcp::Time (0, 0, 1, 0, 24),
569                         dcp::Time (0, 0, 9, 0, 24),
570                         0,
571                         dcp::HAlign::CENTER,
572                         0.9,
573                         dcp::VAlign::TOP,
574                         dcp::Direction::LTR,
575                         "Bottom line",
576                         dcp::Effect::NONE,
577                         dcp::Colour (0, 0, 0),
578                         dcp::Time (0, 0, 0, 0, 24),
579                         dcp::Time (0, 0, 0, 0, 24),
580                         0
581                         )
582                 );
583
584         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
585
586         check_xml (
587                 c.xml_as_string(),
588                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
589                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
590                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
591                 "  <ContentTitleText>Test</ContentTitleText>\n"
592                 "  <IssueDate>2016-04-01T03:52:00.000+00:00</IssueDate>\n"
593                 "  <ReelNumber>1</ReelNumber>\n"
594                 "  <Language>en</Language>\n"
595                 "  <EditRate>24 1</EditRate>\n"
596                 "  <TimeCodeRate>24</TimeCodeRate>\n"
597                 "  <SubtitleList>\n"
598                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
599                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
600                 "        <Text Valign=\"top\" Vposition=\"80\">Top line</Text>\n"
601                 "        <Text Valign=\"top\" Vposition=\"90\">Bottom line</Text>\n"
602                 "      </Subtitle>\n"
603                 "    </Font>\n"
604                 "  </SubtitleList>\n"
605                 "</SubtitleReel>",
606                 {}
607                 );
608 }
609
610
611 /* See the test above */
612 BOOST_AUTO_TEST_CASE (write_subtitles_in_vertical_order_with_bottom_alignment)
613 {
614         dcp::SMPTESubtitleAsset c;
615         c.set_reel_number (1);
616         c.set_language (dcp::LanguageTag("en"));
617         c.set_content_title_text ("Test");
618         c.set_issue_date (dcp::LocalTime ("2016-04-01T03:52:00+00:00"));
619
620         c.add (
621                 make_shared<dcp::SubtitleString>(
622                         string ("Arial"),
623                         false,
624                         false,
625                         false,
626                         dcp::Colour (255, 255, 255),
627                         48,
628                         1.0,
629                         dcp::Time (0, 0, 1, 0, 24),
630                         dcp::Time (0, 0, 9, 0, 24),
631                         0,
632                         dcp::HAlign::CENTER,
633                         0.8,
634                         dcp::VAlign::BOTTOM,
635                         dcp::Direction::LTR,
636                         "Top line",
637                         dcp::Effect::NONE,
638                         dcp::Colour (0, 0, 0),
639                         dcp::Time (0, 0, 0, 0, 24),
640                         dcp::Time (0, 0, 0, 0, 24),
641                         0
642                         )
643                 );
644
645         c.add (
646                 make_shared<dcp::SubtitleString>(
647                         string ("Arial"),
648                         false,
649                         false,
650                         false,
651                         dcp::Colour (255, 255, 255),
652                         48,
653                         1.0,
654                         dcp::Time (0, 0, 1, 0, 24),
655                         dcp::Time (0, 0, 9, 0, 24),
656                         0,
657                         dcp::HAlign::CENTER,
658                         0.7,
659                         dcp::VAlign::BOTTOM,
660                         dcp::Direction::LTR,
661                         "Bottom line",
662                         dcp::Effect::NONE,
663                         dcp::Colour (0, 0, 0),
664                         dcp::Time (0, 0, 0, 0, 24),
665                         dcp::Time (0, 0, 0, 0, 24),
666                         0
667                         )
668                 );
669
670         c._xml_id = "a6c58cff-3e1e-4b38-acec-a42224475ef6";
671
672         check_xml (
673                 c.xml_as_string(),
674                 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
675                 "<SubtitleReel xmlns=\"http://www.smpte-ra.org/schemas/428-7/2010/DCST\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">\n"
676                 "  <Id>urn:uuid:a6c58cff-3e1e-4b38-acec-a42224475ef6</Id>\n"
677                 "  <ContentTitleText>Test</ContentTitleText>\n"
678                 "  <IssueDate>2016-04-01T03:52:00.000+00:00</IssueDate>\n"
679                 "  <ReelNumber>1</ReelNumber>\n"
680                 "  <Language>en</Language>\n"
681                 "  <EditRate>24 1</EditRate>\n"
682                 "  <TimeCodeRate>24</TimeCodeRate>\n"
683                 "  <SubtitleList>\n"
684                 "    <Font AspectAdjust=\"1.0\" Color=\"FFFFFFFF\" Effect=\"none\" EffectColor=\"FF000000\" ID=\"Arial\" Italic=\"no\" Script=\"normal\" Size=\"48\" Underline=\"no\" Weight=\"normal\">\n"
685                 "      <Subtitle SpotNumber=\"1\" TimeIn=\"00:00:01:00\" TimeOut=\"00:00:09:00\" FadeUpTime=\"00:00:00:00\" FadeDownTime=\"00:00:00:00\">\n"
686                 "        <Text Valign=\"bottom\" Vposition=\"80\">Top line</Text>\n"
687                 "        <Text Valign=\"bottom\" Vposition=\"70\">Bottom line</Text>\n"
688                 "      </Subtitle>\n"
689                 "    </Font>\n"
690                 "  </SubtitleList>\n"
691                 "</SubtitleReel>",
692                 {}
693                 );
694 }
695