Coverage Report

Created: 2026-10-14 06:52

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