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
31MovieActivationParameters::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
48MovieActivationParameters::~MovieActivationParameters() { }
49
50void 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
173void 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
228Movie::~Movie()
229{
230 delete fileName;
231}
232
233Movie::Movie(const Object *movieDict)
234{
235 ok = true;
236
237 if (movieDict->isDict()) {
238 parseMovie(movieDict);
239 } else {
240 ok = false;
241 }
242}
243
244Movie::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
258Movie::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
276void 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
282std::unique_ptr<Movie> Movie::copy() const
283{
284 return std::make_unique<Movie>(args: *this);
285}
286

source code of poppler/poppler/Movie.cc