1 //*********************************************************************************
2 // Rendition.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 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 //*********************************************************************************
24
25 #include <math.h>
26 #include "Rendition.h"
27 #include "FileSpec.h"
28
MediaWindowParameters()29 MediaWindowParameters::MediaWindowParameters() {
30 // default values
31 type = windowEmbedded;
32 width = -1;
33 height = -1;
34 relativeTo = windowRelativeToDocument;
35 XPosition = 0.5;
36 YPosition = 0.5;
37 hasTitleBar = gTrue;
38 hasCloseButton = gTrue;
39 isResizeable = gTrue;
40 }
41
~MediaWindowParameters()42 MediaWindowParameters::~MediaWindowParameters() {
43 }
44
parseFWParams(Object * obj)45 void MediaWindowParameters::parseFWParams(Object* obj) {
46 Object tmp;
47
48 if (obj->dictLookup("D", &tmp)->isArray()) {
49 Array * dim = tmp.getArray();
50
51 if (dim->getLength() >= 2) {
52 Object dd;
53 if (dim->get(0, &dd)->isInt()) {
54 width = dd.getInt();
55 }
56 dd.free();
57 if (dim->get(1, &dd)->isInt()) {
58 height = dd.getInt();
59 }
60 dd.free();
61 }
62 }
63 tmp.free();
64
65 if (obj->dictLookup("RT", &tmp)->isInt()) {
66 int t = tmp.getInt();
67 switch(t) {
68 case 0: relativeTo = windowRelativeToDocument; break;
69 case 1: relativeTo = windowRelativeToApplication; break;
70 case 2: relativeTo = windowRelativeToDesktop; break;
71 }
72 }
73 tmp.free();
74
75 if (obj->dictLookup("P",&tmp)->isInt()) {
76 int t = tmp.getInt();
77
78 switch(t) {
79 case 0: // Upper left
80 XPosition = 0.0;
81 YPosition = 0.0;
82 break;
83 case 1: // Upper Center
84 XPosition = 0.5;
85 YPosition = 0.0;
86 break;
87 case 2: // Upper Right
88 XPosition = 1.0;
89 YPosition = 0.0;
90 break;
91 case 3: // Center Left
92 XPosition = 0.0;
93 YPosition = 0.5;
94 break;
95 case 4: // Center
96 XPosition = 0.5;
97 YPosition = 0.5;
98 break;
99 case 5: // Center Right
100 XPosition = 1.0;
101 YPosition = 0.5;
102 break;
103 case 6: // Lower Left
104 XPosition = 0.0;
105 YPosition = 1.0;
106 break;
107 case 7: // Lower Center
108 XPosition = 0.5;
109 YPosition = 1.0;
110 break;
111 case 8: // Lower Right
112 XPosition = 1.0;
113 YPosition = 1.0;
114 break;
115 }
116 }
117 tmp.free();
118
119 if (obj->dictLookup("T", &tmp)->isBool()) {
120 hasTitleBar = tmp.getBool();
121 }
122 tmp.free();
123 if (obj->dictLookup("UC", &tmp)->isBool()) {
124 hasCloseButton = tmp.getBool();
125 }
126 tmp.free();
127 if (obj->dictLookup("R", &tmp)->isInt()) {
128 isResizeable = (tmp.getInt() != 0);
129 }
130 tmp.free();
131
132 }
133
MediaParameters()134 MediaParameters::MediaParameters() {
135 // instanciate to default values
136
137 volume = 100;
138 fittingPolicy = fittingUndefined;
139 autoPlay = gTrue;
140 repeatCount = 1.0;
141 opacity = 1.0;
142 showControls = gFalse;
143 duration = 0;
144 }
145
~MediaParameters()146 MediaParameters::~MediaParameters() {
147 }
148
parseMediaPlayParameters(Object * obj)149 void MediaParameters::parseMediaPlayParameters(Object* obj) {
150
151 Object tmp;
152
153 if (obj->dictLookup("V", &tmp)->isInt()) {
154 volume = tmp.getInt();
155 }
156 tmp.free();
157
158 if (obj->dictLookup("C", &tmp)->isBool()) {
159 showControls = tmp.getBool();
160 }
161 tmp.free();
162
163 if (obj->dictLookup("F", &tmp)->isInt()) {
164 int t = tmp.getInt();
165
166 switch(t) {
167 case 0: fittingPolicy = fittingMeet; break;
168 case 1: fittingPolicy = fittingSlice; break;
169 case 2: fittingPolicy = fittingFill; break;
170 case 3: fittingPolicy = fittingScroll; break;
171 case 4: fittingPolicy = fittingHidden; break;
172 case 5: fittingPolicy = fittingUndefined; break;
173 }
174 }
175 tmp.free();
176
177 // duration parsing
178 // duration's default value is set to 0, which means : intrinsinc media duration
179 if (obj->dictLookup("D", &tmp)->isDict()) {
180 Object oname, ddict, tmp2;
181 if (tmp.dictLookup("S", &oname)->isName()) {
182 char* name = oname.getName();
183 if (!strcmp(name, "F"))
184 duration = -1; // infinity
185 else if (!strcmp(name, "T")) {
186 if (tmp.dictLookup("T", &ddict)->isDict()) {
187 if (ddict.dictLookup("V", &tmp2)->isNum()) {
188 duration = Gulong(tmp2.getNum());
189 }
190 tmp2.free();
191 }
192 ddict.free();
193 }
194 }
195 oname.free();
196 }
197 tmp.free();
198
199
200 if (obj->dictLookup("A", &tmp)->isBool()) {
201 autoPlay = tmp.getBool();
202 }
203 tmp.free();
204
205 if (obj->dictLookup("RC", &tmp)->isNum()) {
206 repeatCount = tmp.getNum();
207 }
208 tmp.free();
209
210 }
211
parseMediaScreenParameters(Object * obj)212 void MediaParameters::parseMediaScreenParameters(Object* obj) {
213 Object tmp;
214
215 if (obj->dictLookup("W", &tmp)->isInt()) {
216 int t = tmp.getInt();
217
218 switch(t) {
219 case 0: windowParams.type = MediaWindowParameters::windowFloating; break;
220 case 1: windowParams.type = MediaWindowParameters::windowFullscreen; break;
221 case 2: windowParams.type = MediaWindowParameters::windowHidden; break;
222 case 3: windowParams.type = MediaWindowParameters::windowEmbedded; break;
223 }
224 }
225 tmp.free();
226
227 // background color
228 if (obj->dictLookup("B", &tmp)->isArray()) {
229 Array* color = tmp.getArray();
230
231 Object component;
232
233 color->get(0, &component);
234 bgColor.r = component.getNum();
235 component.free();
236
237 color->get(1, &component);
238 bgColor.g = component.getNum();
239 component.free();
240
241 color->get(2, &component);
242 bgColor.b = component.getNum();
243 component.free();
244 }
245 tmp.free();
246
247
248 // opacity
249 if (obj->dictLookup("O", &tmp)->isNum()) {
250 opacity = tmp.getNum();
251 }
252 tmp.free();
253
254 if (windowParams.type == MediaWindowParameters::windowFloating) {
255 Object winDict;
256 if (obj->dictLookup("F",&winDict)->isDict()) {
257 windowParams.parseFWParams(&winDict);
258 }
259 winDict.free();
260 }
261 }
262
~MediaRendition()263 MediaRendition::~MediaRendition() {
264 if (fileName)
265 delete fileName;
266 if (contentType)
267 delete contentType;
268
269 if (embeddedStream && (!embeddedStream->decRef())) {
270 delete embeddedStream;
271 }
272 }
273
MediaRendition(Object * obj)274 MediaRendition::MediaRendition(Object* obj) {
275 Object tmp, tmp2;
276 GBool hasClip = gFalse;
277
278 ok = gTrue;
279 fileName = NULL;
280 contentType = NULL;
281 isEmbedded = gFalse;
282 embeddedStream = NULL;
283
284 //
285 // Parse media clip data
286 //
287 if (obj->dictLookup("C", &tmp2)->isDict()) { // media clip
288 hasClip = gTrue;
289 if (tmp2.dictLookup("S", &tmp)->isName()) {
290 if (!strcmp(tmp.getName(), "MCD")) { // media clip data
291 Object obj1, obj2;
292 if (tmp2.dictLookup("D", &obj1)->isDict()) {
293 if (obj1.dictLookup("F", &obj2)->isString()) {
294 fileName = obj2.getString()->copy();
295 }
296 obj2.free();
297 if (obj1.dictLookup("EF", &obj2)->isDict()) {
298 Object embedded;
299 if (obj2.dictLookup("F", &embedded)->isStream()) {
300 isEmbedded = gTrue;
301 embeddedStream = embedded.getStream();
302 // "copy" stream
303 embeddedStream->incRef();
304 }
305 embedded.free();
306 }
307 obj2.free();
308
309 // TODO: D might be a form XObject too
310 } else {
311 error (-1, "Invalid Media Clip Data");
312 ok = gFalse;
313 }
314 obj1.free();
315
316 // FIXME: ignore CT if D is a form XObject
317 if (tmp2.dictLookup("CT", &obj1)->isString()) {
318 contentType = obj1.getString()->copy();
319 }
320 obj1.free();
321 } else if (!strcmp(tmp.getName(), "MCS")) { // media clip data
322 // TODO
323 }
324 } else {
325 error (-1, "Invalid Media Clip");
326 ok = gFalse;
327 }
328 tmp.free();
329 }
330 tmp2.free();
331
332 if (!ok)
333 return;
334
335 //
336 // parse Media Play Parameters
337 if (obj->dictLookup("P", &tmp2)->isDict()) { // media play parameters
338 Object params;
339 if (tmp2.dictLookup("MH", ¶ms)->isDict()) {
340 MH.parseMediaPlayParameters(¶ms);
341 }
342 params.free();
343 if (tmp2.dictLookup("BE", ¶ms)->isDict()) {
344 BE.parseMediaPlayParameters(¶ms);
345 }
346 params.free();
347 } else if (hasClip) {
348 error (-1, "Invalid Media Rendition");
349 ok = gFalse;
350 }
351 tmp2.free();
352
353 //
354 // parse Media Screen Parameters
355 if (obj->dictLookup("SP", &tmp2)->isDict()) { // media screen parameters
356 Object params;
357 if (tmp2.dictLookup("MH", ¶ms)->isDict()) {
358 MH.parseMediaScreenParameters(¶ms);
359 }
360 params.free();
361 if (tmp2.dictLookup("BE", ¶ms)->isDict()) {
362 BE.parseMediaScreenParameters(¶ms);
363 }
364 params.free();
365 }
366 tmp2.free();
367 }
368
outputToFile(FILE * fp)369 void MediaRendition::outputToFile(FILE* fp) {
370 if (!isEmbedded)
371 return;
372
373 embeddedStream->reset();
374
375 while (1) {
376 int c = embeddedStream->getChar();
377 if (c == EOF)
378 break;
379
380 fwrite(&c, 1, 1, fp);
381 }
382
383 }
384
copy()385 MediaRendition *MediaRendition::copy() {
386 // call default copy constructor
387 MediaRendition* new_media = new MediaRendition(*this);
388
389 if (contentType)
390 new_media->contentType = contentType->copy();
391 if (fileName)
392 new_media->fileName = fileName->copy();
393
394 if (new_media->embeddedStream)
395 new_media->embeddedStream->incRef();
396
397 return new_media;
398 }
399
400 // TODO: SelectorRendition
401