a5c94b80cc853d3dee771d678d7b3f5b3c04ed39
[libdcp.git] / src / subtitle_asset.cc
1 /*
2     Copyright (C) 2012 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 #include "subtitle_asset.h"
21
22 using namespace std;
23 using namespace boost;
24 using namespace libdcp;
25
26 SubtitleAsset::SubtitleAsset (string directory, string xml)
27         : Asset (directory, xml)
28         , XMLFile (path().string(), "DCSubtitle")
29 {
30         _subtitle_id = string_node ("SubtitleID");
31         _movie_title = string_node ("MovieTitle");
32         _reel_number = int64_node ("ReelNumber");
33         _language = string_node ("Language");
34
35         ignore_node ("LoadFont");
36
37         list<shared_ptr<FontNode> > font_nodes = sub_nodes<FontNode> ("Font");
38         _load_font_nodes = sub_nodes<LoadFontNode> ("LoadFont");
39
40         /* Now make Subtitle objects to represent the raw XML nodes
41            in a sane way.
42         */
43
44         list<shared_ptr<FontNode> > current_font_nodes;
45         for (list<shared_ptr<FontNode> >::iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
46                 examine_font_node (*i, current_font_nodes);
47         }
48 }
49
50 void
51 SubtitleAsset::examine_font_node (shared_ptr<FontNode> font_node, list<shared_ptr<FontNode> >& current_font_nodes)
52 {
53         current_font_nodes.push_back (font_node);
54
55         for (list<shared_ptr<SubtitleNode> >::iterator j = font_node->subtitle_nodes.begin(); j != font_node->subtitle_nodes.end(); ++j) {
56                 for (list<shared_ptr<TextNode> >::iterator k = (*j)->text_nodes.begin(); k != (*j)->text_nodes.end(); ++k) {
57                         FontNode effective (current_font_nodes);
58                         _subtitles.push_back (
59                                 shared_ptr<Subtitle> (
60                                         new Subtitle (
61                                                 font_id_to_name (effective.id),
62                                                 effective.italic.get(),
63                                                 effective.color.get(),
64                                                 effective.size,
65                                                 (*j)->in,
66                                                 (*j)->out,
67                                                 (*k)->v_position,
68                                                 (*k)->text
69                                                 )
70                                         )
71                                 );
72                 }
73         }
74
75         for (list<shared_ptr<FontNode> >::iterator j = font_node->font_nodes.begin(); j != font_node->font_nodes.end(); ++j) {
76                 examine_font_node (*j, current_font_nodes);
77         }
78
79         current_font_nodes.pop_back ();
80 }
81
82 FontNode::FontNode (xmlpp::Node const * node)
83         : XMLNode (node)
84 {
85         id = string_attribute ("Id");
86         size = optional_int64_attribute ("Size");
87         italic = optional_bool_attribute ("Italic");
88         color = optional_color_attribute ("Color");
89         subtitle_nodes = sub_nodes<SubtitleNode> ("Subtitle");
90         font_nodes = sub_nodes<FontNode> ("Font");
91 }
92
93 FontNode::FontNode (list<shared_ptr<FontNode> > const & font_nodes)
94         : size (0)
95         , italic (false)
96         , color ("FFFFFFFF")
97 {
98         for (list<shared_ptr<FontNode> >::const_iterator i = font_nodes.begin(); i != font_nodes.end(); ++i) {
99                 if (!(*i)->id.empty ()) {
100                         id = (*i)->id;
101                 }
102                 if ((*i)->size != 0) {
103                         size = (*i)->size;
104                 }
105                 if ((*i)->italic) {
106                         italic = (*i)->italic.get ();
107                 }
108                 if ((*i)->color) {
109                         color = (*i)->color.get ();
110                 }
111         }
112 }
113
114 LoadFontNode::LoadFontNode (xmlpp::Node const * node)
115         : XMLNode (node)
116 {
117         id = string_attribute ("Id");
118         uri = string_attribute ("URI");
119 }
120         
121
122 SubtitleNode::SubtitleNode (xmlpp::Node const * node)
123         : XMLNode (node)
124 {
125         in = time_attribute ("TimeIn");
126         out = time_attribute ("TimeOut");
127         text_nodes = sub_nodes<TextNode> ("Text");
128 }
129
130 TextNode::TextNode (xmlpp::Node const * node)
131         : XMLNode (node)
132 {
133         text = content ();
134         v_position = float_attribute ("VPosition");
135 }
136
137 list<shared_ptr<Subtitle> >
138 SubtitleAsset::subtitles_at (Time t) const
139 {
140         list<shared_ptr<Subtitle> > s;
141         for (list<shared_ptr<Subtitle> >::const_iterator i = _subtitles.begin(); i != _subtitles.end(); ++i) {
142                 if ((*i)->in() <= t && t <= (*i)->out ()) {
143                         s.push_back (*i);
144                 }
145         }
146
147         return s;
148 }
149
150 std::string
151 SubtitleAsset::font_id_to_name (string id) const
152 {
153         list<shared_ptr<LoadFontNode> >::const_iterator i = _load_font_nodes.begin();
154         while (i != _load_font_nodes.end() && (*i)->id != id) {
155                 ++i;
156         }
157
158         if (i == _load_font_nodes.end ()) {
159                 return "";
160         }
161
162         if ((*i)->uri == "arial.ttf") {
163                 return "Arial";
164         }
165
166         return "";
167 }
168
169 Subtitle::Subtitle (
170         std::string font,
171         bool italic,
172         Color color,
173         int size,
174         Time in,
175         Time out,
176         float v_position,
177         std::string text
178         )
179         : _font (font)
180         , _italic (italic)
181         , _color (color)
182         , _size (size)
183         , _in (in)
184         , _out (out)
185         , _v_position (v_position)
186         , _text (text)
187 {
188
189 }
190
191 int
192 Subtitle::size_in_pixels (int screen_height) const
193 {
194         /* Size in the subtitle file is given in points as if the screen
195            height is 11 inches, so a 72pt font would be 1/11th of the screen
196            height.
197         */
198         
199         return _size * screen_height / (11 * 72);
200 }