File indexing completed on 2024-04-21 15:38:09

0001 /**
0002  * Copyright (C) 2006 by Koos Vriezen <koos.vriezen@gmail.com>
0003  *
0004  *  This library is free software; you can redistribute it and/or
0005  *  modify it under the terms of the GNU Library General Public
0006  *  License version 2 as published by the Free Software Foundation.
0007  *
0008  *  This library is distributed in the hope that it will be useful,
0009  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0010  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0011  *  Library General Public License for more details.
0012  *
0013  *  You should have received a copy of the GNU Library General Public License
0014  *  along with this library; see the file COPYING.LIB.  If not, write to
0015  *  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
0016  *  Boston, MA 02110-1301, USA.
0017  **/
0018 
0019 #include "config-kmplayer.h"
0020 
0021 #include <qcolor.h>
0022 #include <qtimer.h>
0023 
0024 #include <kdebug.h>
0025 
0026 #include "kmplayer_rp.h"
0027 #include "kmplayer_smil.h"
0028 #include "mediaobject.h"
0029 
0030 using namespace KMPlayer;
0031 
0032 
0033 KDE_NO_CDTOR_EXPORT RP::Imfl::Imfl (NodePtr & d)
0034   : Mrl (d, id_node_imfl),
0035     fit (fit_hidden),
0036     duration (0),
0037     duration_timer (NULL),
0038     needs_scene_img (0) {}
0039 
0040 KDE_NO_CDTOR_EXPORT RP::Imfl::~Imfl () {
0041 }
0042 
0043 KDE_NO_EXPORT void RP::Imfl::closed () {
0044     for (Node *n = firstChild (); n; n = n->nextSibling ())
0045         if (RP::id_node_head == n->id) {
0046             Attribute *a = static_cast <Element *> (n)->attributes ().first ();
0047             for (; a; a = a->nextSibling ()) {
0048                 if (Ids::attr_width == a->name ()) {
0049                     size.width = a->value ().toInt ();
0050                 } else if (Ids::attr_height == a->name ()) {
0051                     size.height = a->value ().toInt ();
0052                 } else if (a->name () == "duration") {
0053                     int dur;
0054                     parseTime (a->value ().toLower (), dur);
0055                     duration = dur;
0056                 }
0057             }
0058         }
0059     Mrl::closed ();
0060 }
0061 
0062 KDE_NO_EXPORT void RP::Imfl::defer () {
0063     kDebug () << "RP::Imfl::defer ";
0064     setState (state_deferred);
0065     for (Node *n = firstChild (); n; n = n->nextSibling ())
0066         if (n->id == RP::id_node_image && !n->active ())
0067             n->activate ();
0068 }
0069 
0070 KDE_NO_EXPORT void RP::Imfl::activate () {
0071     kDebug () << "RP::Imfl::activate ";
0072     resolved = true;
0073     setState (state_activated);
0074     int timings_count = 0;
0075     for (Node *n = firstChild (); n; n = n->nextSibling ())
0076         switch (n->id) {
0077             case RP::id_node_crossfade:
0078             case RP::id_node_fadein:
0079             case RP::id_node_fadeout:
0080             case RP::id_node_fill:
0081             case RP::id_node_wipe:
0082             case RP::id_node_viewchange:
0083                 n->activate (); // set their start timers
0084                 timings_count++;
0085                 break;
0086             case RP::id_node_image:
0087                 if (!n->active ())
0088                     n->activate ();
0089                 break;
0090         }
0091     if (duration > 0)
0092         duration_timer = document ()->post (this,
0093                 new TimerPosting (duration * 10));
0094     else if (!timings_count)
0095         finish ();
0096 }
0097 
0098 KDE_NO_EXPORT void RP::Imfl::finish () {
0099     kDebug () << "RP::Imfl::finish ";
0100     Mrl::finish ();
0101     if (duration_timer) {
0102         document ()->cancelPosting (duration_timer);
0103         duration_timer = 0;
0104     }
0105     for (NodePtr n = firstChild (); n; n = n->nextSibling ())
0106         if (n->unfinished ())
0107             n->finish ();
0108 }
0109 
0110 KDE_NO_EXPORT void RP::Imfl::deactivate () {
0111     kDebug () << "RP::Imfl::deactivate ";
0112     if (unfinished ())
0113         finish ();
0114     else if (duration_timer) {
0115         document ()->cancelPosting (duration_timer);
0116         duration_timer = 0;
0117     }
0118     if (!active ())
0119         return; // calling finish might call deactivate() as well
0120     setState (state_deactivated);
0121     for (NodePtr n = firstChild (); n; n = n->nextSibling ())
0122         if (n->active ())
0123             n->deactivate ();
0124     rp_surface = (Surface *) role (RoleChildDisplay, NULL);
0125 }
0126 
0127 KDE_NO_EXPORT void RP::Imfl::message (MessageType msg, void *content) {
0128     switch (msg) {
0129         case MsgEventTimer:
0130             duration_timer = 0;
0131             if (unfinished ())
0132                 finish ();
0133             return;
0134         case MsgChildFinished:
0135             if (unfinished () && !duration_timer) {
0136                 for (Node *n = firstChild (); n; n = n->nextSibling ())
0137                     switch (n->id) {
0138                         case RP::id_node_crossfade:
0139                         case RP::id_node_fadein:
0140                         case RP::id_node_fadeout:
0141                         case RP::id_node_fill:
0142                             if (n->unfinished ())
0143                                 return;
0144                     }
0145                 finish ();
0146             }
0147             return;
0148         default:
0149             break;
0150     }
0151     Mrl::message (msg, content);
0152 }
0153 
0154 KDE_NO_EXPORT void RP::Imfl::accept (Visitor * v) {
0155     v->visit (this);
0156 }
0157 
0158 KDE_NO_EXPORT Surface *RP::Imfl::surface () {
0159     if (!rp_surface) {
0160         rp_surface = (Surface *) Mrl::role (RoleChildDisplay, this);
0161         if (rp_surface && size.isEmpty ())
0162             size = rp_surface->bounds.size;
0163     }
0164     return rp_surface.ptr ();
0165 }
0166 
0167 KDE_NO_EXPORT Node *RP::Imfl::childFromTag (const QString & tag) {
0168     QByteArray ba = tag.toLatin1 ();
0169     const char *ctag = ba.constData ();
0170     if (!strcmp (ctag, "head"))
0171         return new DarkNode (m_doc, "head", RP::id_node_head);
0172     else if (!strcmp (ctag, "image"))
0173         return new RP::Image (m_doc);
0174     else if (!strcmp (ctag, "fill"))
0175         return new RP::Fill (m_doc);
0176     else if (!strcmp (ctag, "wipe"))
0177         return new RP::Wipe (m_doc);
0178     else if (!strcmp (ctag, "viewchange"))
0179         return new RP::ViewChange (m_doc);
0180     else if (!strcmp (ctag, "crossfade"))
0181         return new RP::Crossfade (m_doc);
0182     else if (!strcmp (ctag, "fadein"))
0183         return new RP::Fadein (m_doc);
0184     else if (!strcmp (ctag, "fadeout"))
0185         return new RP::Fadeout (m_doc);
0186     return NULL;
0187 }
0188 
0189 KDE_NO_EXPORT void RP::Imfl::repaint () {
0190     if (!active ()) {
0191         kWarning () << "Spurious Imfl repaint";
0192     } else if (surface () && !size.isEmpty ()) {
0193         rp_surface->markDirty ();
0194         rp_surface->repaint (SRect (0, 0, size));
0195     }
0196 }
0197 
0198 KDE_NO_CDTOR_EXPORT RP::Image::Image (NodePtr & doc)
0199  : Mrl (doc, id_node_image) {
0200     view_mode = WindowMode;
0201 }
0202 
0203 KDE_NO_CDTOR_EXPORT RP::Image::~Image () {
0204 }
0205 
0206 KDE_NO_EXPORT void RP::Image::closed () {
0207     src = getAttribute (Ids::attr_name);
0208     Mrl::closed ();
0209 }
0210 
0211 KDE_NO_EXPORT void RP::Image::activate () {
0212     kDebug () << "RP::Image::activate";
0213     setState (state_activated);
0214     isPlayable (); // update src attribute
0215     if (!media_info)
0216         media_info = new MediaInfo (this, MediaManager::Image);
0217     media_info->wget (absolutePath ());
0218 }
0219 
0220 KDE_NO_EXPORT void RP::Image::begin () {
0221     Node::begin ();
0222 }
0223 
0224 KDE_NO_EXPORT void RP::Image::deactivate () {
0225     if (img_surface) {
0226         img_surface->remove ();
0227         img_surface = NULL;
0228     }
0229     setState (state_deactivated);
0230     postpone_lock = 0L;
0231     delete media_info;
0232     media_info = NULL;
0233 }
0234 
0235 KDE_NO_EXPORT void RP::Image::message (MessageType msg, void *content) {
0236     if (msg == MsgMediaReady) {
0237         if (media_info)
0238             dataArrived ();
0239     } else {
0240         Mrl::message (msg, content);
0241     }
0242 }
0243 
0244 KDE_NO_EXPORT void RP::Image::dataArrived () {
0245     kDebug () << "RP::Image::remoteReady";
0246     ImageMedia *im = media_info->media ? (ImageMedia *)media_info->media : NULL;
0247     if (im && !im->isEmpty ()) {
0248         size.width = im->cached_img->width;
0249         size.height = im->cached_img->height;
0250     }
0251     postpone_lock = 0L;
0252 }
0253 
0254 KDE_NO_EXPORT bool RP::Image::isReady (bool postpone_if_not) {
0255     if (media_info->downloading () && postpone_if_not)
0256         postpone_lock = document ()->postpone ();
0257     return !media_info->downloading ();
0258 }
0259 
0260 KDE_NO_EXPORT Surface *RP::Image::surface () {
0261     ImageMedia *im = media_info && media_info->media
0262         ? (ImageMedia *)media_info->media : NULL;
0263     if (im && !img_surface && !im->isEmpty ()) {
0264         Node * p = parentNode ();
0265         if (p && p->id == RP::id_node_imfl) {
0266             Surface *ps = static_cast <RP::Imfl *> (p)->surface ();
0267             if (ps)
0268                 img_surface = ps->createSurface (this,
0269                         SRect (0, 0, size));
0270         }
0271     }
0272     return img_surface;
0273 }
0274 
0275 KDE_NO_CDTOR_EXPORT RP::TimingsBase::TimingsBase (NodePtr & d, const short i)
0276  : Element (d, i), x (0), y (0), w (0), h (0), start (0), duration (0),
0277    start_timer (NULL), duration_timer (NULL), update_timer (NULL) {}
0278 
0279 KDE_NO_EXPORT void RP::TimingsBase::activate () {
0280     setState (state_activated);
0281     x = y = w = h = 0;
0282     srcx = srcy = srcw = srch = 0;
0283     for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
0284         if (a->name () == Ids::attr_target) {
0285             for (Node *n = parentNode()->firstChild(); n; n= n->nextSibling())
0286                 if (static_cast <Element *> (n)->
0287                         getAttribute ("handle") == a->value ())
0288                     target = n;
0289         } else if (a->name () == "start") {
0290             int dur;
0291             parseTime (a->value ().toLower (), dur);
0292             start = dur;
0293         } else if (a->name () == "duration") {
0294             int dur;
0295             parseTime (a->value ().toLower (), dur);
0296             duration = dur;
0297         } else if (a->name () == "dstx") {
0298             x = a->value ().toInt ();
0299         } else if (a->name () == "dsty") {
0300             y = a->value ().toInt ();
0301         } else if (a->name () == "dstw") {
0302             w = a->value ().toInt ();
0303         } else if (a->name () == "dsth") {
0304             h = a->value ().toInt ();
0305         } else if (a->name () == "srcx") {
0306             srcx = a->value ().toInt ();
0307         } else if (a->name () == "srcy") {
0308             srcy = a->value ().toInt ();
0309         } else if (a->name () == "srcw") {
0310             srcw = a->value ().toInt ();
0311         } else if (a->name () == "srch") {
0312             srch = a->value ().toInt ();
0313         }
0314     }
0315     start_timer = document ()->post (this, new TimerPosting (start *10));
0316 }
0317 
0318 KDE_NO_EXPORT void RP::TimingsBase::deactivate () {
0319     if (unfinished ())
0320         finish ();
0321     else
0322         cancelTimers ();
0323     setState (state_deactivated);
0324 }
0325 
0326 KDE_NO_EXPORT void RP::TimingsBase::message (MessageType msg, void *content) {
0327     switch (msg) {
0328         case MsgEventTimer: {
0329             TimerPosting *te = static_cast <TimerPosting *> (content);
0330             if (te == update_timer && duration > 0) {
0331                 update (100 * 10 * ++curr_step / duration);
0332                 te->interval = true;
0333             } else if (te == start_timer) {
0334                 start_timer = 0;
0335                 duration_timer = document()->post (this,
0336                         new TimerPosting (duration * 10));
0337                 begin ();
0338             } else if (te == duration_timer) {
0339                 duration_timer = 0;
0340                 update (100);
0341                 finish ();
0342             }
0343             break;
0344         }
0345         case MsgEventPostponed: {
0346             PostponedEvent *pe = static_cast <PostponedEvent *> (content);
0347             if (!pe->is_postponed) {
0348                 document_postponed.disconnect ();
0349                 update (duration > 0 ? 0 : 100);
0350             }
0351             break;
0352         }
0353         default:
0354             Element::message (msg, content);
0355     }
0356 }
0357 
0358 KDE_NO_EXPORT void RP::TimingsBase::begin () {
0359     progress = 0;
0360     setState (state_began);
0361     if (target)
0362         target->begin ();
0363     if (duration > 0) {
0364         steps = duration / 10; // 10/s updates
0365         update_timer = document ()->post (this, new TimerPosting (100)); // 50ms
0366         curr_step = 1;
0367     }
0368 }
0369 
0370 KDE_NO_EXPORT void RP::TimingsBase::update (int percentage) {
0371     progress = percentage;
0372     Node *p = parentNode ();
0373     if (p->id == RP::id_node_imfl)
0374         static_cast <RP::Imfl *> (p)->repaint ();
0375 }
0376 
0377 KDE_NO_EXPORT void RP::TimingsBase::finish () {
0378     progress = 100;
0379     cancelTimers ();
0380     document_postponed.disconnect ();
0381     Element::finish ();
0382 }
0383 
0384 KDE_NO_EXPORT void RP::TimingsBase::cancelTimers () {
0385     if (start_timer) {
0386         document ()->cancelPosting (start_timer);
0387         start_timer = 0;
0388     } else if (duration_timer) {
0389         document ()->cancelPosting (duration_timer);
0390         duration_timer = 0;
0391     }
0392     if (update_timer) {
0393         document ()->cancelPosting (update_timer);
0394         update_timer = 0;
0395     }
0396 }
0397 
0398 KDE_NO_EXPORT void RP::Crossfade::activate () {
0399     TimingsBase::activate ();
0400 }
0401 
0402 KDE_NO_EXPORT void RP::Crossfade::begin () {
0403     //kDebug () << "RP::Crossfade::begin";
0404     TimingsBase::begin ();
0405     if (target && target->id == id_node_image) {
0406         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0407         if (!img->isReady (true))
0408             document_postponed.connect (document(), MsgEventPostponed, this);
0409         else
0410             update (duration > 0 ? 0 : 100);
0411     }
0412 }
0413 
0414 KDE_NO_EXPORT void RP::Crossfade::accept (Visitor * v) {
0415     v->visit (this);
0416 }
0417 
0418 KDE_NO_EXPORT void RP::Fadein::activate () {
0419     // pickup color from Fill that should be declared before this node
0420     from_color = 0;
0421     TimingsBase::activate ();
0422 }
0423 
0424 KDE_NO_EXPORT void RP::Fadein::begin () {
0425     //kDebug () << "RP::Fadein::begin";
0426     TimingsBase::begin ();
0427     if (target && target->id == id_node_image) {
0428         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0429         if (!img->isReady (true))
0430             document_postponed.connect (document(), MsgEventPostponed, this);
0431         else
0432             update (duration > 0 ? 0 : 100);
0433     }
0434 }
0435 
0436 KDE_NO_EXPORT void RP::Fadein::accept (Visitor * v) {
0437     v->visit (this);
0438 }
0439 
0440 KDE_NO_EXPORT void RP::Fadeout::activate () {
0441     to_color = QColor (getAttribute ("color")).rgb ();
0442     TimingsBase::activate ();
0443 }
0444 
0445 KDE_NO_EXPORT void RP::Fadeout::begin () {
0446     //kDebug () << "RP::Fadeout::begin";
0447     TimingsBase::begin ();
0448 }
0449 
0450 KDE_NO_EXPORT void RP::Fadeout::accept (Visitor * v) {
0451     v->visit (this);
0452 }
0453 
0454 KDE_NO_EXPORT void RP::Fill::activate () {
0455     color = QColor (getAttribute ("color")).rgb ();
0456     TimingsBase::activate ();
0457 }
0458 
0459 KDE_NO_EXPORT void RP::Fill::begin () {
0460     setState (state_began);
0461     update (0);
0462 }
0463 
0464 KDE_NO_EXPORT void RP::Fill::accept (Visitor * v) {
0465     v->visit (this);
0466 }
0467 
0468 KDE_NO_EXPORT void RP::Wipe::activate () {
0469     //TODO implement 'type="push"'
0470     QString dir = getAttribute ("direction").toLower ();
0471     direction = dir_right;
0472     if (dir == QString::fromLatin1 ("left"))
0473         direction = dir_left;
0474     else if (dir == QString::fromLatin1 ("up"))
0475         direction = dir_up;
0476     else if (dir == QString::fromLatin1 ("down"))
0477         direction = dir_down;
0478     TimingsBase::activate ();
0479 }
0480 
0481 KDE_NO_EXPORT void RP::Wipe::begin () {
0482     //kDebug () << "RP::Wipe::begin";
0483     TimingsBase::begin ();
0484     if (target && target->id == id_node_image) {
0485         RP::Image * img = static_cast <RP::Image *> (target.ptr ());
0486         if (!img->isReady (true))
0487             document_postponed.connect (document(), MsgEventPostponed, this);
0488         else
0489             update (duration > 0 ? 0 : 100);
0490     }
0491 }
0492 
0493 KDE_NO_EXPORT void RP::Wipe::accept (Visitor * v) {
0494     v->visit (this);
0495 }
0496 
0497 KDE_NO_EXPORT void RP::ViewChange::activate () {
0498     TimingsBase::activate ();
0499 }
0500 
0501 KDE_NO_EXPORT void RP::ViewChange::begin () {
0502     kDebug () << "RP::ViewChange::begin";
0503     setState (state_began);
0504     Node *p = parentNode ();
0505     if (p->id == RP::id_node_imfl)
0506         static_cast <RP::Imfl *> (p)->needs_scene_img++;
0507     update (0);
0508 }
0509 
0510 KDE_NO_EXPORT void RP::ViewChange::finish () {
0511     Node *p = parentNode ();
0512     if (p && p->id == RP::id_node_imfl)
0513         static_cast <RP::Imfl *> (p)->needs_scene_img--;
0514     TimingsBase::finish ();
0515 }
0516 
0517 KDE_NO_EXPORT void RP::ViewChange::accept (Visitor * v) {
0518     v->visit (this);
0519 }