No-op: remove all trailing whitespace.
[dcpomatic.git] / src / lib / video_content_scale.cc
1 /*
2     Copyright (C) 2013-2015 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 "video_content_scale.h"
21 #include "video_content.h"
22 #include "ratio.h"
23 #include "safe_stringstream.h"
24 #include "util.h"
25 #include <libcxml/cxml.h>
26 #include <libxml++/libxml++.h>
27 #include <boost/optional.hpp>
28
29 #include "i18n.h"
30
31 using std::vector;
32 using std::string;
33 using std::min;
34 using std::cout;
35 using boost::shared_ptr;
36 using boost::optional;
37
38 vector<VideoContentScale> VideoContentScale::_scales;
39
40 VideoContentScale::VideoContentScale (Ratio const * r)
41         : _ratio (r)
42         , _scale (true)
43 {
44
45 }
46
47 VideoContentScale::VideoContentScale ()
48         : _ratio (0)
49         , _scale (false)
50 {
51
52 }
53
54 VideoContentScale::VideoContentScale (bool scale)
55         : _ratio (0)
56         , _scale (scale)
57 {
58
59 }
60
61 VideoContentScale::VideoContentScale (shared_ptr<cxml::Node> node)
62         : _ratio (0)
63         , _scale (true)
64 {
65         optional<string> r = node->optional_string_child ("Ratio");
66         if (r) {
67                 _ratio = Ratio::from_id (r.get ());
68         } else {
69                 _scale = node->bool_child ("Scale");
70         }
71 }
72
73 void
74 VideoContentScale::as_xml (xmlpp::Node* node) const
75 {
76         if (_ratio) {
77                 node->add_child("Ratio")->add_child_text (_ratio->id ());
78         } else {
79                 node->add_child("Scale")->add_child_text (_scale ? "1" : "0");
80         }
81 }
82
83 string
84 VideoContentScale::id () const
85 {
86         SafeStringStream s;
87
88         if (_ratio) {
89                 s << _ratio->id ();
90         } else {
91                 s << (_scale ? "S1" : "S0");
92         }
93
94         return s.str ();
95 }
96
97 string
98 VideoContentScale::name () const
99 {
100         if (_ratio) {
101                 return _ratio->nickname ();
102         }
103
104         if (_scale) {
105                 return _("No stretch");
106         }
107
108         return _("No scale");
109 }
110
111 VideoContentScale
112 VideoContentScale::from_id (string id)
113 {
114         Ratio const * r = Ratio::from_id (id);
115         if (r) {
116                 return VideoContentScale (r);
117         }
118
119         if (id == "S0") {
120                 return VideoContentScale (false);
121         }
122
123         return VideoContentScale (true);
124 }
125
126 /** @param display_container Size of the container that we are displaying this content in.
127  *  @param film_container The size of the film's image.
128  */
129 dcp::Size
130 VideoContentScale::size (shared_ptr<const VideoContent> c, dcp::Size display_container, dcp::Size film_container) const
131 {
132         /* Work out the size of the content if it were put inside film_container */
133
134         dcp::Size const video_size_after_crop = c->video_size_after_crop ();
135
136         dcp::Size size;
137
138         if (_ratio) {
139                 /* Stretch to fit the requested ratio */
140                 size = fit_ratio_within (_ratio->ratio (), film_container);
141         } else if (_scale || video_size_after_crop.width > film_container.width || video_size_after_crop.height > film_container.height) {
142                 /* Scale, preserving aspect ratio; this is either if we have been asked to scale with no stretch
143                    or if the unscaled content is too big for film_container.
144                 */
145                 size = fit_ratio_within (video_size_after_crop.ratio(), film_container);
146         } else {
147                 /* No stretch nor scale */
148                 size = video_size_after_crop;
149         }
150
151         /* Now scale it down if the display container is smaller than the film container */
152         if (display_container != film_container) {
153                 float const scale = min (
154                         float (display_container.width) / film_container.width,
155                         float (display_container.height) / film_container.height
156                         );
157
158                 size.width = rint (size.width * scale);
159                 size.height = rint (size.height * scale);
160         }
161
162         return size;
163 }
164
165 void
166 VideoContentScale::setup_scales ()
167 {
168         vector<Ratio const *> ratios = Ratio::all ();
169         for (vector<Ratio const *>::const_iterator i = ratios.begin(); i != ratios.end(); ++i) {
170                 _scales.push_back (VideoContentScale (*i));
171         }
172
173         _scales.push_back (VideoContentScale (true));
174         _scales.push_back (VideoContentScale (false));
175 }
176
177 bool
178 operator== (VideoContentScale const & a, VideoContentScale const & b)
179 {
180         return (a.ratio() == b.ratio() && a.scale() == b.scale());
181 }
182
183 bool
184 operator!= (VideoContentScale const & a, VideoContentScale const & b)
185 {
186         return (a.ratio() != b.ratio() || a.scale() != b.scale());
187 }