1 /**
2 * Copyright (C) 2006 by Koos Vriezen <koos.vriezen@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License version 2 as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
12 *
13 * You should have received a copy of the GNU Library General Public License
14 * along with this library; see the file COPYING.LIB. If not, write to
15 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
16 * Boston, MA 02110-1301, USA.
17 **/
18
19 #include "config-kmplayer.h"
20
21 #include <qcolor.h>
22 #include <qtimer.h>
23
24 #include <kdebug.h>
25
26 #include "kmplayer_rp.h"
27 #include "kmplayer_smil.h"
28 #include "mediaobject.h"
29
30 using namespace KMPlayer;
31
32
Imfl(NodePtr & d)33 KDE_NO_CDTOR_EXPORT RP::Imfl::Imfl (NodePtr & d)
34 : Mrl (d, id_node_imfl),
35 fit (fit_hidden),
36 duration (0),
37 duration_timer (NULL),
38 needs_scene_img (0) {}
39
~Imfl()40 KDE_NO_CDTOR_EXPORT RP::Imfl::~Imfl () {
41 }
42
closed()43 KDE_NO_EXPORT void RP::Imfl::closed () {
44 for (Node *n = firstChild (); n; n = n->nextSibling ())
45 if (RP::id_node_head == n->id) {
46 Attribute *a = static_cast <Element *> (n)->attributes ().first ();
47 for (; a; a = a->nextSibling ()) {
48 if (Ids::attr_width == a->name ()) {
49 size.width = a->value ().toInt ();
50 } else if (Ids::attr_height == a->name ()) {
51 size.height = a->value ().toInt ();
52 } else if (a->name () == "duration") {
53 int dur;
54 parseTime (a->value ().toLower (), dur);
55 duration = dur;
56 }
57 }
58 }
59 Mrl::closed ();
60 }
61
defer()62 KDE_NO_EXPORT void RP::Imfl::defer () {
63 kDebug () << "RP::Imfl::defer ";
64 setState (state_deferred);
65 for (Node *n = firstChild (); n; n = n->nextSibling ())
66 if (n->id == RP::id_node_image && !n->active ())
67 n->activate ();
68 }
69
activate()70 KDE_NO_EXPORT void RP::Imfl::activate () {
71 kDebug () << "RP::Imfl::activate ";
72 resolved = true;
73 setState (state_activated);
74 int timings_count = 0;
75 for (Node *n = firstChild (); n; n = n->nextSibling ())
76 switch (n->id) {
77 case RP::id_node_crossfade:
78 case RP::id_node_fadein:
79 case RP::id_node_fadeout:
80 case RP::id_node_fill:
81 case RP::id_node_wipe:
82 case RP::id_node_viewchange:
83 n->activate (); // set their start timers
84 timings_count++;
85 break;
86 case RP::id_node_image:
87 if (!n->active ())
88 n->activate ();
89 break;
90 }
91 if (duration > 0)
92 duration_timer = document ()->post (this,
93 new TimerPosting (duration * 10));
94 else if (!timings_count)
95 finish ();
96 }
97
finish()98 KDE_NO_EXPORT void RP::Imfl::finish () {
99 kDebug () << "RP::Imfl::finish ";
100 Mrl::finish ();
101 if (duration_timer) {
102 document ()->cancelPosting (duration_timer);
103 duration_timer = 0;
104 }
105 for (NodePtr n = firstChild (); n; n = n->nextSibling ())
106 if (n->unfinished ())
107 n->finish ();
108 }
109
deactivate()110 KDE_NO_EXPORT void RP::Imfl::deactivate () {
111 kDebug () << "RP::Imfl::deactivate ";
112 if (unfinished ())
113 finish ();
114 else if (duration_timer) {
115 document ()->cancelPosting (duration_timer);
116 duration_timer = 0;
117 }
118 if (!active ())
119 return; // calling finish might call deactivate() as well
120 setState (state_deactivated);
121 for (NodePtr n = firstChild (); n; n = n->nextSibling ())
122 if (n->active ())
123 n->deactivate ();
124 rp_surface = (Surface *) role (RoleChildDisplay, NULL);
125 }
126
message(MessageType msg,void * content)127 KDE_NO_EXPORT void RP::Imfl::message (MessageType msg, void *content) {
128 switch (msg) {
129 case MsgEventTimer:
130 duration_timer = 0;
131 if (unfinished ())
132 finish ();
133 return;
134 case MsgChildFinished:
135 if (unfinished () && !duration_timer) {
136 for (Node *n = firstChild (); n; n = n->nextSibling ())
137 switch (n->id) {
138 case RP::id_node_crossfade:
139 case RP::id_node_fadein:
140 case RP::id_node_fadeout:
141 case RP::id_node_fill:
142 if (n->unfinished ())
143 return;
144 }
145 finish ();
146 }
147 return;
148 default:
149 break;
150 }
151 Mrl::message (msg, content);
152 }
153
accept(Visitor * v)154 KDE_NO_EXPORT void RP::Imfl::accept (Visitor * v) {
155 v->visit (this);
156 }
157
surface()158 KDE_NO_EXPORT Surface *RP::Imfl::surface () {
159 if (!rp_surface) {
160 rp_surface = (Surface *) Mrl::role (RoleChildDisplay, this);
161 if (rp_surface && size.isEmpty ())
162 size = rp_surface->bounds.size;
163 }
164 return rp_surface.ptr ();
165 }
166
childFromTag(const QString & tag)167 KDE_NO_EXPORT Node *RP::Imfl::childFromTag (const QString & tag) {
168 QByteArray ba = tag.toLatin1 ();
169 const char *ctag = ba.constData ();
170 if (!strcmp (ctag, "head"))
171 return new DarkNode (m_doc, "head", RP::id_node_head);
172 else if (!strcmp (ctag, "image"))
173 return new RP::Image (m_doc);
174 else if (!strcmp (ctag, "fill"))
175 return new RP::Fill (m_doc);
176 else if (!strcmp (ctag, "wipe"))
177 return new RP::Wipe (m_doc);
178 else if (!strcmp (ctag, "viewchange"))
179 return new RP::ViewChange (m_doc);
180 else if (!strcmp (ctag, "crossfade"))
181 return new RP::Crossfade (m_doc);
182 else if (!strcmp (ctag, "fadein"))
183 return new RP::Fadein (m_doc);
184 else if (!strcmp (ctag, "fadeout"))
185 return new RP::Fadeout (m_doc);
186 return NULL;
187 }
188
repaint()189 KDE_NO_EXPORT void RP::Imfl::repaint () {
190 if (!active ()) {
191 kWarning () << "Spurious Imfl repaint";
192 } else if (surface () && !size.isEmpty ()) {
193 rp_surface->markDirty ();
194 rp_surface->repaint (SRect (0, 0, size));
195 }
196 }
197
Image(NodePtr & doc)198 KDE_NO_CDTOR_EXPORT RP::Image::Image (NodePtr & doc)
199 : Mrl (doc, id_node_image) {
200 view_mode = WindowMode;
201 }
202
~Image()203 KDE_NO_CDTOR_EXPORT RP::Image::~Image () {
204 }
205
closed()206 KDE_NO_EXPORT void RP::Image::closed () {
207 src = getAttribute (Ids::attr_name);
208 Mrl::closed ();
209 }
210
activate()211 KDE_NO_EXPORT void RP::Image::activate () {
212 kDebug () << "RP::Image::activate";
213 setState (state_activated);
214 isPlayable (); // update src attribute
215 if (!media_info)
216 media_info = new MediaInfo (this, MediaManager::Image);
217 media_info->wget (absolutePath ());
218 }
219
begin()220 KDE_NO_EXPORT void RP::Image::begin () {
221 Node::begin ();
222 }
223
deactivate()224 KDE_NO_EXPORT void RP::Image::deactivate () {
225 if (img_surface) {
226 img_surface->remove ();
227 img_surface = NULL;
228 }
229 setState (state_deactivated);
230 postpone_lock = 0L;
231 delete media_info;
232 media_info = NULL;
233 }
234
message(MessageType msg,void * content)235 KDE_NO_EXPORT void RP::Image::message (MessageType msg, void *content) {
236 if (msg == MsgMediaReady) {
237 if (media_info)
238 dataArrived ();
239 } else {
240 Mrl::message (msg, content);
241 }
242 }
243
dataArrived()244 KDE_NO_EXPORT void RP::Image::dataArrived () {
245 kDebug () << "RP::Image::remoteReady";
246 ImageMedia *im = media_info->media ? (ImageMedia *)media_info->media : NULL;
247 if (im && !im->isEmpty ()) {
248 size.width = im->cached_img->width;
249 size.height = im->cached_img->height;
250 }
251 postpone_lock = 0L;
252 }
253
isReady(bool postpone_if_not)254 KDE_NO_EXPORT bool RP::Image::isReady (bool postpone_if_not) {
255 if (media_info->downloading () && postpone_if_not)
256 postpone_lock = document ()->postpone ();
257 return !media_info->downloading ();
258 }
259
surface()260 KDE_NO_EXPORT Surface *RP::Image::surface () {
261 ImageMedia *im = media_info && media_info->media
262 ? (ImageMedia *)media_info->media : NULL;
263 if (im && !img_surface && !im->isEmpty ()) {
264 Node * p = parentNode ();
265 if (p && p->id == RP::id_node_imfl) {
266 Surface *ps = static_cast <RP::Imfl *> (p)->surface ();
267 if (ps)
268 img_surface = ps->createSurface (this,
269 SRect (0, 0, size));
270 }
271 }
272 return img_surface;
273 }
274
TimingsBase(NodePtr & d,const short i)275 KDE_NO_CDTOR_EXPORT RP::TimingsBase::TimingsBase (NodePtr & d, const short i)
276 : Element (d, i), x (0), y (0), w (0), h (0), start (0), duration (0),
277 start_timer (NULL), duration_timer (NULL), update_timer (NULL) {}
278
activate()279 KDE_NO_EXPORT void RP::TimingsBase::activate () {
280 setState (state_activated);
281 x = y = w = h = 0;
282 srcx = srcy = srcw = srch = 0;
283 for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
284 if (a->name () == Ids::attr_target) {
285 for (Node *n = parentNode()->firstChild(); n; n= n->nextSibling())
286 if (static_cast <Element *> (n)->
287 getAttribute ("handle") == a->value ())
288 target = n;
289 } else if (a->name () == "start") {
290 int dur;
291 parseTime (a->value ().toLower (), dur);
292 start = dur;
293 } else if (a->name () == "duration") {
294 int dur;
295 parseTime (a->value ().toLower (), dur);
296 duration = dur;
297 } else if (a->name () == "dstx") {
298 x = a->value ().toInt ();
299 } else if (a->name () == "dsty") {
300 y = a->value ().toInt ();
301 } else if (a->name () == "dstw") {
302 w = a->value ().toInt ();
303 } else if (a->name () == "dsth") {
304 h = a->value ().toInt ();
305 } else if (a->name () == "srcx") {
306 srcx = a->value ().toInt ();
307 } else if (a->name () == "srcy") {
308 srcy = a->value ().toInt ();
309 } else if (a->name () == "srcw") {
310 srcw = a->value ().toInt ();
311 } else if (a->name () == "srch") {
312 srch = a->value ().toInt ();
313 }
314 }
315 start_timer = document ()->post (this, new TimerPosting (start *10));
316 }
317
deactivate()318 KDE_NO_EXPORT void RP::TimingsBase::deactivate () {
319 if (unfinished ())
320 finish ();
321 else
322 cancelTimers ();
323 setState (state_deactivated);
324 }
325
message(MessageType msg,void * content)326 KDE_NO_EXPORT void RP::TimingsBase::message (MessageType msg, void *content) {
327 switch (msg) {
328 case MsgEventTimer: {
329 TimerPosting *te = static_cast <TimerPosting *> (content);
330 if (te == update_timer && duration > 0) {
331 update (100 * 10 * ++curr_step / duration);
332 te->interval = true;
333 } else if (te == start_timer) {
334 start_timer = 0;
335 duration_timer = document()->post (this,
336 new TimerPosting (duration * 10));
337 begin ();
338 } else if (te == duration_timer) {
339 duration_timer = 0;
340 update (100);
341 finish ();
342 }
343 break;
344 }
345 case MsgEventPostponed: {
346 PostponedEvent *pe = static_cast <PostponedEvent *> (content);
347 if (!pe->is_postponed) {
348 document_postponed.disconnect ();
349 update (duration > 0 ? 0 : 100);
350 }
351 break;
352 }
353 default:
354 Element::message (msg, content);
355 }
356 }
357
begin()358 KDE_NO_EXPORT void RP::TimingsBase::begin () {
359 progress = 0;
360 setState (state_began);
361 if (target)
362 target->begin ();
363 if (duration > 0) {
364 steps = duration / 10; // 10/s updates
365 update_timer = document ()->post (this, new TimerPosting (100)); // 50ms
366 curr_step = 1;
367 }
368 }
369
update(int percentage)370 KDE_NO_EXPORT void RP::TimingsBase::update (int percentage) {
371 progress = percentage;
372 Node *p = parentNode ();
373 if (p->id == RP::id_node_imfl)
374 static_cast <RP::Imfl *> (p)->repaint ();
375 }
376
finish()377 KDE_NO_EXPORT void RP::TimingsBase::finish () {
378 progress = 100;
379 cancelTimers ();
380 document_postponed.disconnect ();
381 Element::finish ();
382 }
383
cancelTimers()384 KDE_NO_EXPORT void RP::TimingsBase::cancelTimers () {
385 if (start_timer) {
386 document ()->cancelPosting (start_timer);
387 start_timer = 0;
388 } else if (duration_timer) {
389 document ()->cancelPosting (duration_timer);
390 duration_timer = 0;
391 }
392 if (update_timer) {
393 document ()->cancelPosting (update_timer);
394 update_timer = 0;
395 }
396 }
397
activate()398 KDE_NO_EXPORT void RP::Crossfade::activate () {
399 TimingsBase::activate ();
400 }
401
begin()402 KDE_NO_EXPORT void RP::Crossfade::begin () {
403 //kDebug () << "RP::Crossfade::begin";
404 TimingsBase::begin ();
405 if (target && target->id == id_node_image) {
406 RP::Image * img = static_cast <RP::Image *> (target.ptr ());
407 if (!img->isReady (true))
408 document_postponed.connect (document(), MsgEventPostponed, this);
409 else
410 update (duration > 0 ? 0 : 100);
411 }
412 }
413
accept(Visitor * v)414 KDE_NO_EXPORT void RP::Crossfade::accept (Visitor * v) {
415 v->visit (this);
416 }
417
activate()418 KDE_NO_EXPORT void RP::Fadein::activate () {
419 // pickup color from Fill that should be declared before this node
420 from_color = 0;
421 TimingsBase::activate ();
422 }
423
begin()424 KDE_NO_EXPORT void RP::Fadein::begin () {
425 //kDebug () << "RP::Fadein::begin";
426 TimingsBase::begin ();
427 if (target && target->id == id_node_image) {
428 RP::Image * img = static_cast <RP::Image *> (target.ptr ());
429 if (!img->isReady (true))
430 document_postponed.connect (document(), MsgEventPostponed, this);
431 else
432 update (duration > 0 ? 0 : 100);
433 }
434 }
435
accept(Visitor * v)436 KDE_NO_EXPORT void RP::Fadein::accept (Visitor * v) {
437 v->visit (this);
438 }
439
activate()440 KDE_NO_EXPORT void RP::Fadeout::activate () {
441 to_color = QColor (getAttribute ("color")).rgb ();
442 TimingsBase::activate ();
443 }
444
begin()445 KDE_NO_EXPORT void RP::Fadeout::begin () {
446 //kDebug () << "RP::Fadeout::begin";
447 TimingsBase::begin ();
448 }
449
accept(Visitor * v)450 KDE_NO_EXPORT void RP::Fadeout::accept (Visitor * v) {
451 v->visit (this);
452 }
453
activate()454 KDE_NO_EXPORT void RP::Fill::activate () {
455 color = QColor (getAttribute ("color")).rgb ();
456 TimingsBase::activate ();
457 }
458
begin()459 KDE_NO_EXPORT void RP::Fill::begin () {
460 setState (state_began);
461 update (0);
462 }
463
accept(Visitor * v)464 KDE_NO_EXPORT void RP::Fill::accept (Visitor * v) {
465 v->visit (this);
466 }
467
activate()468 KDE_NO_EXPORT void RP::Wipe::activate () {
469 //TODO implement 'type="push"'
470 QString dir = getAttribute ("direction").toLower ();
471 direction = dir_right;
472 if (dir == QString::fromLatin1 ("left"))
473 direction = dir_left;
474 else if (dir == QString::fromLatin1 ("up"))
475 direction = dir_up;
476 else if (dir == QString::fromLatin1 ("down"))
477 direction = dir_down;
478 TimingsBase::activate ();
479 }
480
begin()481 KDE_NO_EXPORT void RP::Wipe::begin () {
482 //kDebug () << "RP::Wipe::begin";
483 TimingsBase::begin ();
484 if (target && target->id == id_node_image) {
485 RP::Image * img = static_cast <RP::Image *> (target.ptr ());
486 if (!img->isReady (true))
487 document_postponed.connect (document(), MsgEventPostponed, this);
488 else
489 update (duration > 0 ? 0 : 100);
490 }
491 }
492
accept(Visitor * v)493 KDE_NO_EXPORT void RP::Wipe::accept (Visitor * v) {
494 v->visit (this);
495 }
496
activate()497 KDE_NO_EXPORT void RP::ViewChange::activate () {
498 TimingsBase::activate ();
499 }
500
begin()501 KDE_NO_EXPORT void RP::ViewChange::begin () {
502 kDebug () << "RP::ViewChange::begin";
503 setState (state_began);
504 Node *p = parentNode ();
505 if (p->id == RP::id_node_imfl)
506 static_cast <RP::Imfl *> (p)->needs_scene_img++;
507 update (0);
508 }
509
finish()510 KDE_NO_EXPORT void RP::ViewChange::finish () {
511 Node *p = parentNode ();
512 if (p && p->id == RP::id_node_imfl)
513 static_cast <RP::Imfl *> (p)->needs_scene_img--;
514 TimingsBase::finish ();
515 }
516
accept(Visitor * v)517 KDE_NO_EXPORT void RP::ViewChange::accept (Visitor * v) {
518 v->visit (this);
519 }
520