1 | //********************************************************************************* |
2 | // Movie.cc |
3 | //--------------------------------------------------------------------------------- |
4 | // |
5 | //--------------------------------------------------------------------------------- |
6 | // Hugo Mercier <hmercier31[at]gmail.com> (c) 2008 |
7 | // Pino Toscano <pino@kde.org> (c) 2008 |
8 | // Carlos Garcia Campos <carlosgc@gnome.org> (c) 2010 |
9 | // Albert Astals Cid <aacid@kde.org> (c) 2010, 2017-2019, 2022 |
10 | // Evgeny Stambulchik <fnevgeny@gmail.com> (c) 2019 |
11 | // |
12 | // This program is free software; you can redistribute it and/or modify |
13 | // it under the terms of the GNU General Public License as published by |
14 | // the Free Software Foundation; either version 2 of the License, or |
15 | // (at your option) any later version. |
16 | // |
17 | // This program is distributed in the hope that it will be useful, |
18 | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | // GNU General Public License for more details. |
21 | // |
22 | // You should have received a copy of the GNU General Public License |
23 | // along with this program; if not, write to the Free Software |
24 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
25 | //********************************************************************************* |
26 | |
27 | #include <cmath> |
28 | #include "Movie.h" |
29 | #include "FileSpec.h" |
30 | |
31 | MovieActivationParameters::MovieActivationParameters() |
32 | { |
33 | // default values |
34 | floatingWindow = false; |
35 | xPosition = 0.5; |
36 | yPosition = 0.5; |
37 | rate = 1.0; |
38 | volume = 100; |
39 | showControls = false; |
40 | synchronousPlay = false; |
41 | repeatMode = repeatModeOnce; |
42 | start.units = 0; |
43 | duration.units = 0; |
44 | znum = 1; |
45 | zdenum = 1; |
46 | } |
47 | |
48 | MovieActivationParameters::~MovieActivationParameters() { } |
49 | |
50 | void MovieActivationParameters::parseMovieActivation(const Object *aDict) |
51 | { |
52 | Object obj1 = aDict->dictLookup(key: "Start" ); |
53 | if (obj1.isInt()) { |
54 | // If it is representable as an integer (subject to the implementation limit for |
55 | // integers, as described in Appendix C), it should be specified as such. |
56 | |
57 | start.units = obj1.getInt(); |
58 | } else if (obj1.isString()) { |
59 | // If it is not representable as an integer, it should be specified as an 8-byte |
60 | // string representing a 64-bit twos-complement integer, most significant |
61 | // byte first. |
62 | |
63 | // UNSUPPORTED |
64 | } else if (obj1.isArray()) { |
65 | Array *a = obj1.getArray(); |
66 | |
67 | Object tmp = a->get(i: 0); |
68 | if (tmp.isInt()) { |
69 | start.units = tmp.getInt(); |
70 | } |
71 | if (tmp.isString()) { |
72 | // UNSUPPORTED |
73 | } |
74 | |
75 | tmp = a->get(i: 1); |
76 | if (tmp.isInt()) { |
77 | start.units_per_second = tmp.getInt(); |
78 | } |
79 | } |
80 | |
81 | obj1 = aDict->dictLookup(key: "Duration" ); |
82 | if (obj1.isInt()) { |
83 | duration.units = obj1.getInt(); |
84 | } else if (obj1.isString()) { |
85 | // UNSUPPORTED |
86 | } else if (obj1.isArray()) { |
87 | Array *a = obj1.getArray(); |
88 | |
89 | Object tmp = a->get(i: 0); |
90 | if (tmp.isInt()) { |
91 | duration.units = tmp.getInt(); |
92 | } |
93 | if (tmp.isString()) { |
94 | // UNSUPPORTED |
95 | } |
96 | |
97 | tmp = a->get(i: 1); |
98 | if (tmp.isInt()) { |
99 | duration.units_per_second = tmp.getInt(); |
100 | } |
101 | } |
102 | |
103 | obj1 = aDict->dictLookup(key: "Rate" ); |
104 | if (obj1.isNum()) { |
105 | rate = obj1.getNum(); |
106 | } |
107 | |
108 | obj1 = aDict->dictLookup(key: "Volume" ); |
109 | if (obj1.isNum()) { |
110 | // convert volume to [0 100] |
111 | volume = int((obj1.getNum() + 1.0) * 50); |
112 | } |
113 | |
114 | obj1 = aDict->dictLookup(key: "ShowControls" ); |
115 | if (obj1.isBool()) { |
116 | showControls = obj1.getBool(); |
117 | } |
118 | |
119 | obj1 = aDict->dictLookup(key: "Synchronous" ); |
120 | if (obj1.isBool()) { |
121 | synchronousPlay = obj1.getBool(); |
122 | } |
123 | |
124 | obj1 = aDict->dictLookup(key: "Mode" ); |
125 | if (obj1.isName()) { |
126 | const char *name = obj1.getName(); |
127 | if (!strcmp(s1: name, s2: "Once" )) { |
128 | repeatMode = repeatModeOnce; |
129 | } else if (!strcmp(s1: name, s2: "Open" )) { |
130 | repeatMode = repeatModeOpen; |
131 | } else if (!strcmp(s1: name, s2: "Repeat" )) { |
132 | repeatMode = repeatModeRepeat; |
133 | } else if (!strcmp(s1: name, s2: "Palindrome" )) { |
134 | repeatMode = repeatModePalindrome; |
135 | } |
136 | } |
137 | |
138 | obj1 = aDict->dictLookup(key: "FWScale" ); |
139 | if (obj1.isArray()) { |
140 | // the presence of that entry implies that the movie is to be played |
141 | // in a floating window |
142 | floatingWindow = true; |
143 | |
144 | Array *scale = obj1.getArray(); |
145 | if (scale->getLength() >= 2) { |
146 | Object tmp = scale->get(i: 1); |
147 | if (tmp.isInt()) { |
148 | znum = tmp.getInt(); |
149 | } |
150 | tmp = scale->get(i: 1); |
151 | if (tmp.isInt()) { |
152 | zdenum = tmp.getInt(); |
153 | } |
154 | } |
155 | } |
156 | |
157 | obj1 = aDict->dictLookup(key: "FWPosition" ); |
158 | if (obj1.isArray()) { |
159 | Array *pos = obj1.getArray(); |
160 | if (pos->getLength() >= 2) { |
161 | Object tmp = pos->get(i: 0); |
162 | if (tmp.isNum()) { |
163 | xPosition = tmp.getNum(); |
164 | } |
165 | tmp = pos->get(i: 1); |
166 | if (tmp.isNum()) { |
167 | yPosition = tmp.getNum(); |
168 | } |
169 | } |
170 | } |
171 | } |
172 | |
173 | void Movie::parseMovie(const Object *movieDict) |
174 | { |
175 | fileName = nullptr; |
176 | rotationAngle = 0; |
177 | width = -1; |
178 | height = -1; |
179 | showPoster = false; |
180 | |
181 | Object obj1 = movieDict->dictLookup(key: "F" ); |
182 | Object obj2 = getFileSpecNameForPlatform(fileSpec: &obj1); |
183 | if (obj2.isString()) { |
184 | fileName = obj2.getString()->copy(); |
185 | } else { |
186 | error(category: errSyntaxError, pos: -1, msg: "Invalid Movie" ); |
187 | ok = false; |
188 | return; |
189 | } |
190 | |
191 | obj1 = movieDict->dictLookup(key: "Aspect" ); |
192 | if (obj1.isArray()) { |
193 | Array *aspect = obj1.getArray(); |
194 | if (aspect->getLength() >= 2) { |
195 | Object tmp = aspect->get(i: 0); |
196 | if (tmp.isNum()) { |
197 | width = (int)floor(x: tmp.getNum() + 0.5); |
198 | } |
199 | tmp = aspect->get(i: 1); |
200 | if (tmp.isNum()) { |
201 | height = (int)floor(x: tmp.getNum() + 0.5); |
202 | } |
203 | } |
204 | } |
205 | |
206 | obj1 = movieDict->dictLookup(key: "Rotate" ); |
207 | if (obj1.isInt()) { |
208 | // round up to 90° |
209 | rotationAngle = (((obj1.getInt() + 360) % 360) % 90) * 90; |
210 | } |
211 | |
212 | // |
213 | // movie poster |
214 | // |
215 | poster = movieDict->dictLookupNF(key: "Poster" ).copy(); |
216 | if (!poster.isNull()) { |
217 | if (poster.isRef() || poster.isStream()) { |
218 | showPoster = true; |
219 | } else if (poster.isBool()) { |
220 | showPoster = poster.getBool(); |
221 | poster.setToNull(); |
222 | } else { |
223 | poster.setToNull(); |
224 | } |
225 | } |
226 | } |
227 | |
228 | Movie::~Movie() |
229 | { |
230 | delete fileName; |
231 | } |
232 | |
233 | Movie::Movie(const Object *movieDict) |
234 | { |
235 | ok = true; |
236 | |
237 | if (movieDict->isDict()) { |
238 | parseMovie(movieDict); |
239 | } else { |
240 | ok = false; |
241 | } |
242 | } |
243 | |
244 | Movie::Movie(const Object *movieDict, const Object *aDict) |
245 | { |
246 | ok = true; |
247 | |
248 | if (movieDict->isDict()) { |
249 | parseMovie(movieDict); |
250 | if (aDict->isDict()) { |
251 | MA.parseMovieActivation(aDict); |
252 | } |
253 | } else { |
254 | ok = false; |
255 | } |
256 | } |
257 | |
258 | Movie::Movie(const Movie &other) |
259 | { |
260 | ok = other.ok; |
261 | rotationAngle = other.rotationAngle; |
262 | width = other.width; |
263 | height = other.height; |
264 | showPoster = other.showPoster; |
265 | MA = other.MA; |
266 | |
267 | poster = other.poster.copy(); |
268 | |
269 | if (other.fileName) { |
270 | fileName = other.fileName->copy(); |
271 | } else { |
272 | fileName = nullptr; |
273 | } |
274 | } |
275 | |
276 | void Movie::getFloatingWindowSize(int *widthA, int *heightA) |
277 | { |
278 | *widthA = int(width * double(MA.znum) / MA.zdenum); |
279 | *heightA = int(height * double(MA.znum) / MA.zdenum); |
280 | } |
281 | |
282 | std::unique_ptr<Movie> Movie::copy() const |
283 | { |
284 | return std::make_unique<Movie>(args: *this); |
285 | } |
286 | |