In-line run of subs_in_out so that it gets the environment more easily.
[libdcp.git] / src / subtitle_string.cc
1 /*
2     Copyright (C) 2012-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 /** @file  src/subtitle_string.cc
36  *  @brief SubtitleString class
37  */
38
39
40 #include "compose.hpp"
41 #include "subtitle_string.h"
42 #include "xml.h"
43 #include <cmath>
44
45
46 using std::dynamic_pointer_cast;
47 using std::max;
48 using std::min;
49 using std::ostream;
50 using std::shared_ptr;
51 using std::string;
52 using std::vector;
53 using boost::optional;
54 using namespace dcp;
55
56
57 SubtitleString::SubtitleString (
58         optional<string> font,
59         bool italic,
60         bool bold,
61         bool underline,
62         Colour colour,
63         int size,
64         float aspect_adjust,
65         Time in,
66         Time out,
67         float h_position,
68         HAlign h_align,
69         float v_position,
70         VAlign v_align,
71         float z_position,
72         Direction direction,
73         string text,
74         Effect effect,
75         Colour effect_colour,
76         Time fade_up_time,
77         Time fade_down_time,
78         float space_before,
79         vector<Ruby> rubies
80         )
81         : Subtitle(in, out, h_position, h_align, v_position, v_align, z_position, fade_up_time, fade_down_time)
82         , _font (font)
83         , _italic (italic)
84         , _bold (bold)
85         , _underline (underline)
86         , _colour (colour)
87         , _size (size)
88         , _aspect_adjust (aspect_adjust)
89         , _direction (direction)
90         , _text (text)
91         , _effect (effect)
92         , _effect_colour (effect_colour)
93         , _space_before (space_before)
94         , _rubies(rubies)
95 {
96         _aspect_adjust = max(min(_aspect_adjust, 4.0f), 0.25f);
97 }
98
99
100 float
101 SubtitleString::size_in_pixels (int screen_height) const
102 {
103         /* Size in the subtitle file is given in points as if the screen
104            height is 11 inches, so a 72pt font would be 1/11th of the screen
105            height.
106         */
107
108         return _size * static_cast<float>(screen_height) / (11.0f * 72.0f);
109 }
110
111
112 bool
113 dcp::operator== (SubtitleString const & a, SubtitleString const & b)
114 {
115         return (
116                 a.font() == b.font() &&
117                 a.italic() == b.italic() &&
118                 a.bold() == b.bold() &&
119                 a.underline() == b.underline() &&
120                 a.colour() == b.colour() &&
121                 a.size() == b.size() &&
122                 fabs (a.aspect_adjust() - b.aspect_adjust()) < ASPECT_ADJUST_EPSILON &&
123                 a.in() == b.in() &&
124                 a.out() == b.out() &&
125                 a.h_position() == b.h_position() &&
126                 a.h_align() == b.h_align() &&
127                 a.v_position() == b.v_position() &&
128                 a.v_align() == b.v_align() &&
129                 a.z_position() == b.z_position() &&
130                 a.direction() == b.direction() &&
131                 a.text() == b.text() &&
132                 a.effect() == b.effect() &&
133                 a.effect_colour() == b.effect_colour() &&
134                 a.fade_up_time() == b.fade_up_time() &&
135                 a.fade_down_time() == b.fade_down_time() &&
136                 fabs (a.space_before() - b.space_before()) < SPACE_BEFORE_EPSILON &&
137                 a.rubies() == b.rubies()
138                 );
139 }
140
141
142 bool
143 dcp::operator!= (SubtitleString const & a, SubtitleString const & b)
144 {
145         return !(a == b);
146 }
147
148
149 ostream&
150 dcp::operator<< (ostream& s, SubtitleString const & sub)
151 {
152         s << "\n`" << sub.text() << "' from " << sub.in() << " to " << sub.out() << ";\n"
153           << "fade up " << sub.fade_up_time() << ", fade down " << sub.fade_down_time() << ";\n"
154           << "font " << sub.font().get_value_or ("[default]") << ", ";
155
156         if (sub.italic()) {
157                 s << "italic, ";
158         } else {
159                 s << "non-italic, ";
160         }
161
162         if (sub.bold()) {
163                 s << "bold, ";
164         } else {
165                 s << "normal, ";
166         }
167
168         if (sub.underline()) {
169                 s << "underlined, ";
170         }
171
172         s << "size " << sub.size() << ", aspect " << sub.aspect_adjust()
173           << ", colour (" << sub.colour().r << ", " << sub.colour().g << ", " << sub.colour().b << ")"
174           << ", vpos " << sub.v_position() << ", valign " << ((int) sub.v_align())
175           << ", hpos " << sub.h_position() << ", halign " << ((int) sub.h_align())
176           << ", zpos " << sub.z_position()
177           << ", direction " << ((int) sub.direction())
178           << ", effect " << ((int) sub.effect())
179           << ", effect colour (" << sub.effect_colour().r << ", " << sub.effect_colour().g << ", " << sub.effect_colour().b << ")"
180           << ", space before " << sub.space_before();
181
182         for (auto ruby: sub.rubies()) {
183                 s << ", ruby " << ruby.base << " " << ruby.annotation;
184         }
185
186         return s;
187 }
188
189
190 bool
191 SubtitleString::equals(shared_ptr<const Subtitle> other_sub, EqualityOptions const& options, NoteHandler note) const
192 {
193         if (!Subtitle::equals(other_sub, options, note)) {
194                 return false;
195         }
196
197         auto other = dynamic_pointer_cast<const SubtitleString>(other_sub);
198         if (!other) {
199                 note(NoteType::ERROR, "Subtitle types differ: string vs image");
200                 return false;
201         }
202
203         bool same = true;
204
205         if (_font != other->_font) {
206                 note(NoteType::ERROR, String::compose("subtitle font differs: %1 vs %2", _font.get_value_or("[none]"), other->_font.get_value_or("[none]")));
207                 same = false;
208         }
209
210         if (_italic != other->_italic) {
211                 note(NoteType::ERROR, String::compose("subtitle italic flag differs: %1 vs %2", _italic ? "true" : "false", other->_italic ? "true" : "false"));
212                 same = false;
213         }
214
215         if (_bold != other->_bold) {
216                 note(NoteType::ERROR, String::compose("subtitle bold flag differs: %1 vs %2", _bold ? "true" : "false", other->_bold ? "true" : "false"));
217                 same = false;
218         }
219
220         if (_underline != other->_underline) {
221                 note(NoteType::ERROR, String::compose("subtitle underline flag differs: %1 vs %2", _underline ? "true" : "false", other->_underline ? "true" : "false"));
222                 same = false;
223         }
224
225         if (_colour != other->_colour) {
226                 note(NoteType::ERROR, String::compose("subtitle colour differs: %1 vs %2", _colour.to_rgb_string(), other->_colour.to_rgb_string()));
227                 same = false;
228         }
229
230         if (_size != other->_size) {
231                 note(NoteType::ERROR, String::compose("subtitle size differs: %1 vs %2", _size, other->_size));
232                 same = false;
233         }
234
235         if (_aspect_adjust != other->_aspect_adjust) {
236                 note(NoteType::ERROR, String::compose("subtitle aspect_adjust differs: %1 vs %2", _aspect_adjust, other->_aspect_adjust));
237                 same = false;
238         }
239
240         if (_direction != other->_direction) {
241                 note(NoteType::ERROR, String::compose("subtitle direction differs: %1 vs %2", direction_to_string(_direction), direction_to_string(other->_direction)));
242                 same = false;
243         }
244
245         if (_text != other->_text) {
246                 note(NoteType::ERROR, String::compose("subtitle text differs: %1 vs %2", _text, other->_text));
247                 same = false;
248         }
249
250         if (_effect != other->_effect) {
251                 note(NoteType::ERROR, String::compose("subtitle effect differs: %1 vs %2", effect_to_string(_effect), effect_to_string(other->_effect)));
252                 same = false;
253         }
254
255         if (_effect_colour != other->_effect_colour) {
256                 note(NoteType::ERROR, String::compose("subtitle effect colour differs: %1 vs %2", _effect_colour.to_rgb_string(), other->_effect_colour.to_rgb_string()));
257                 same = false;
258         }
259
260         if (_space_before != other->_space_before) {
261                 note(NoteType::ERROR, String::compose("subtitle space before differs: %1 vs %2", _space_before, other->_space_before));
262                 same = false;
263         }
264
265         if (_rubies != other->_rubies) {
266                 note(NoteType::ERROR, "rubies differ");
267                 same = false;
268         }
269
270         return same;
271 }
272