File indexing completed on 2024-04-14 15:01:02

0001 /**
0002  * Copyright (C) 2005-2007 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 <stdlib.h>
0022 
0023 #include <qtextstream.h>
0024 #include <qcolor.h>
0025 #include <qfont.h>
0026 #include <qapplication.h>
0027 #include <qregexp.h>
0028 #include <qtimer.h>
0029 #include <QBuffer>
0030 
0031 #include <kdebug.h>
0032 #include <kurl.h>
0033 #include <kmimetype.h>
0034 #include <kio/job.h>
0035 #include <kio/jobclasses.h>
0036 
0037 #include "kmplayer_smil.h"
0038 #include "kmplayer_rp.h"
0039 #include "expression.h"
0040 #include "mediaobject.h"
0041 
0042 using namespace KMPlayer;
0043 
0044 namespace KMPlayer {
0045 
0046 static const unsigned int begin_timer_id = (unsigned int) 3;
0047 static const unsigned int dur_timer_id = (unsigned int) 4;
0048 static const unsigned int anim_timer_id = (unsigned int) 5;
0049 static const unsigned int trans_timer_id = (unsigned int) 6;
0050 static const unsigned int trans_out_timer_id = (unsigned int) 7;
0051 
0052 }
0053 
0054 /* Intrinsic duration
0055  *  DurTime         |    EndTime     |
0056  *  =======================================================================
0057  *    DurMedia      |   DurMedia     | wait for event
0058  *        0         |   DurMedia     | only wait for child elements
0059  *    DurMedia      |       0        | intrinsic duration finished
0060  */
0061 //-----------------------------------------------------------------------------
0062 
0063 KDE_NO_EXPORT bool KMPlayer::parseTime (const QString & vl, int & dur) {
0064     QByteArray ba = vl.toLatin1 ();
0065     const char *cval = ba.constData ();
0066     if (!cval) {
0067         dur = 0;
0068         return false;
0069     }
0070     int sign = 1;
0071     bool fp_seen = false;
0072     QString num;
0073     const char * p = cval;
0074     for ( ; *p; p++ ) {
0075         if (*p == '+') {
0076             if (!num.isEmpty ())
0077                 break;
0078             else
0079                 sign = 1;
0080         } else if (*p == '-') {
0081             if (!num.isEmpty ())
0082                 break;
0083             else
0084                 sign = -1;
0085         } else if (*p >= '0' && *p <= '9') {
0086             num += QChar (*p);
0087         } else if (*p == '.') {
0088             if (fp_seen)
0089                 break;
0090             else
0091                 num += QChar (*p);
0092             fp_seen = true;
0093         } else if (*p == ' ') {
0094             if (!num.isEmpty ())
0095                 break;
0096         } else if (*p == ':') {
0097             dur = Mrl::parseTimeString (vl);
0098             return dur != 0;
0099         } else
0100             break;
0101     }
0102     bool ok = false;
0103     double t;
0104     if (!num.isEmpty ())
0105         t = sign * num.toDouble (&ok);
0106     if (ok) {
0107         for ( ; *p; p++ ) {
0108             if (*p == 'm') {
0109                 t *= 60;
0110                 break;
0111             } else if (*p == 'h') {
0112                 t *= 60 * 60;
0113                 break;
0114             } else if (*p != ' ')
0115                 break;
0116         }
0117         dur = (int) (100 * t);
0118     } else {
0119         dur = 0;
0120         return false;
0121     }
0122     return true;
0123 }
0124 
0125 static SMIL::Region *findRegion2 (Node *p, const QString &id) {
0126     TrieString regionname_attr ("regionName");
0127     for (Node *c = p->firstChild (); c; c = c->nextSibling ()) {
0128         if (c->id == SMIL::id_node_region) {
0129             SMIL::Region *r = static_cast <SMIL::Region *> (c);
0130             QString a = r->getAttribute (regionname_attr);
0131             if (a.isEmpty ())
0132                 a = r->getAttribute (Ids::attr_id);
0133             if ((a.isEmpty () && id.isEmpty ()) || a == id)
0134                 return r;
0135         }
0136         SMIL::Region * r = findRegion2 (c, id);
0137         if (r)
0138             return r;
0139     }
0140     return 0L;
0141 }
0142 
0143 static SMIL::RegionBase *findRegion (Node *n, const QString &id) {
0144     SMIL::RegionBase *region = NULL;
0145     SMIL::Smil *smil = SMIL::Smil::findSmilNode (n);
0146     if (smil) {
0147         SMIL::Layout *layout = convertNode <SMIL::Layout> (smil->layout_node);
0148         region = findRegion2 (layout, id);
0149         if (!region)
0150             region = convertNode <SMIL::RegionBase> (layout->root_layout);
0151     }
0152     return region;
0153 }
0154 
0155 static Node *findHeadNode (SMIL::Smil *s)
0156 {
0157     for (Node *h = s ? s->firstChild () : NULL; h; h = h->nextSibling ())
0158         if (SMIL::id_node_head == h->id)
0159             return h;
0160     return NULL;
0161 }
0162 
0163 static SMIL::Transition *findTransition (Node *n, const QString &id)
0164 {
0165     Node *head = findHeadNode (SMIL::Smil::findSmilNode (n));
0166     if (head)
0167         for (Node *c = head->firstChild (); c; c = c->nextSibling())
0168             if (c->id == SMIL::id_node_transition &&
0169                     id == static_cast <Element *> (c)->
0170                     getAttribute (Ids::attr_id))
0171                 return static_cast <SMIL::Transition *> (c);
0172     return 0L;
0173 }
0174 
0175 static bool parseTransitionParam (Node *n, TransitionModule &m, Runtime *r,
0176         const TrieString &para, const QString &val) {
0177     if (para == "transIn") {
0178         SMIL::Transition *t = findTransition (n, val);
0179         if (t) {
0180             m.trans_in = t;
0181             r->trans_in_dur = t->dur;
0182         } else {
0183             kWarning() << "Transition " << val << " not found in head";
0184         }
0185     } else if (para == "transOut") {
0186         m.trans_out = findTransition (n, val);
0187         if (!m.trans_out)
0188             kWarning() << "Transition " << val << " not found in head";
0189     } else {
0190         return false;
0191     }
0192     return true;
0193 }
0194 
0195 static Node *findLocalNodeById (Node *n, const QString & id) {
0196     SMIL::Smil *s = SMIL::Smil::findSmilNode (n);
0197     if (s)
0198         return s->document ()->getElementById (s, id, false);
0199     return 0L;
0200 }
0201 
0202 static Fit parseFit (const char *cval) {
0203     Fit fit;
0204     if (!cval)
0205         fit = fit_hidden;
0206     else if (!strcmp (cval, "fill"))
0207         fit = fit_fill;
0208     else if (!strcmp (cval, "hidden"))
0209         fit = fit_hidden;
0210     else if (!strcmp (cval, "meet"))
0211         fit = fit_meet;
0212     else if (!strcmp (cval, "scroll"))
0213         fit = fit_scroll;
0214     else if (!strcmp (cval, "slice"))
0215         fit = fit_slice;
0216     else
0217         fit = fit_default;
0218     return fit;
0219 }
0220 
0221 //-----------------------------------------------------------------------------
0222 
0223 PostponedEvent::PostponedEvent (bool postponed)
0224  : is_postponed (postponed) {}
0225 
0226 //-----------------------------------------------------------------------------
0227 
0228 Runtime::DurationItem::DurationItem ()
0229     : durval (DurTimer), offset (0), next (NULL) {}
0230 
0231 Runtime::DurationItem &
0232 Runtime::DurationItem::operator = (const Runtime::DurationItem &d) {
0233     durval = d.durval;
0234     offset = d.offset;
0235     payload = d.payload;
0236     connection.assign (&d.connection);
0237     return *this;
0238 }
0239 
0240 bool Runtime::DurationItem::matches (const Duration dur, const Posting *post) {
0241     return dur == durval &&
0242         connection.signaler () == post->source.ptr () &&
0243         ((Duration) MsgStateChanged != durval || post->payload == payload);
0244 }
0245 
0246 void Runtime::DurationItem::clear() {
0247     durval = DurTimer;
0248     offset = 0;
0249     payload = NULL;
0250     connection.disconnect ();
0251     if (next) {
0252         next->clear ();
0253         delete next;
0254         next = NULL;
0255     }
0256 }
0257 
0258 static Runtime::Fill getDefaultFill (NodePtr n) {
0259     for (NodePtr p = n->parentNode (); p; p = p->parentNode ()) {
0260         Runtime *rt = static_cast <Runtime *> (p->role (RoleTiming));
0261         if (rt) {
0262             if (rt->fill_def != Runtime::fill_inherit)
0263                 return rt->fill_def;
0264             else if (rt->fill == Runtime::fill_default)
0265                 return rt->fill_active;//assume parent figured out this
0266         } else if (p->id == SMIL::id_node_smil)
0267             break;
0268     }
0269     return Runtime::fill_auto;
0270 }
0271 
0272 KDE_NO_CDTOR_EXPORT Runtime::Runtime (Element *e)
0273  : begin_timer (NULL),
0274    duration_timer (NULL),
0275    started_timer (NULL),
0276    stopped_timer (NULL),
0277    fill_active (fill_auto),
0278    element (NULL) {
0279     init();
0280     element = e;
0281 }
0282 
0283 
0284 KDE_NO_CDTOR_EXPORT Runtime::~Runtime () {
0285     if (begin_timer)
0286         element->document ()->cancelPosting (begin_timer);
0287     if (duration_timer)
0288         element->document ()->cancelPosting (duration_timer);
0289     element = NULL;
0290     init ();
0291 }
0292 
0293 KDE_NO_EXPORT void Runtime::init ()
0294 {
0295     if (element && begin_timer) {
0296         element->document ()->cancelPosting (begin_timer);
0297         begin_timer = NULL;
0298     }
0299     if (element && duration_timer) {
0300         element->document ()->cancelPosting (duration_timer);
0301         duration_timer = NULL;
0302     }
0303     repeat = repeat_count = 1;
0304     trans_in_dur = 0;
0305     timingstate = TimingsInit;
0306     for (int i = 0; i < (int) DurTimeLast; i++)
0307         durations [i].clear ();
0308     endTime ().durval = DurMedia;
0309     start_time = finish_time = 0;
0310     fill = fill_default;
0311     fill_def = fill_inherit;
0312 }
0313 
0314 KDE_NO_EXPORT void Runtime::initialize ()
0315 {
0316     if (fill == fill_default) {
0317         if (fill_def == fill_inherit)
0318             fill_active = getDefaultFill (element);
0319         else
0320             fill_active = fill_def;
0321     }
0322     timingstate = Runtime::TimingsInitialized;
0323 }
0324 
0325 static
0326 void setDurationItem (Node *n, const QString &val, Runtime::DurationItem *itm) {
0327     int dur = -2; // also 0 for 'media' duration, so it will not update then
0328     QString vs = val.trimmed ();
0329     QString vl = vs.toLower ();
0330     QByteArray ba = vl.toLatin1 ();
0331     const char *cval = ba.constData ();
0332     int offset = 0;
0333     VirtualVoid *payload = NULL;
0334     if (cval && cval[0]) {
0335         QString idref;
0336         const char * p = cval;
0337         if (parseTime (vl, offset)) {
0338             dur = Runtime::DurTimer;
0339         } else if (!strncmp (cval, "id(", 3)) {
0340             p = strchr (cval + 3, ')');
0341             if (p) {
0342                 idref = vs.mid (3, p - cval - 3);
0343                 p++;
0344             }
0345             if (*p) {
0346                 const char *q = strchr (p, '(');
0347                 if (q)
0348                     p = q;
0349             }
0350         } else if (!strncmp (cval, "indefinite", 10)) {
0351             offset = -1;
0352             dur = Runtime::DurIndefinite;
0353         } else if (!strncmp (cval, "media", 5)) {
0354             dur = Runtime::DurMedia;
0355         }
0356         if (dur == -2) {
0357             NodePtr target;
0358             const char * q = p;
0359             if (idref.isEmpty ()) {
0360                 bool last_esc = false;
0361                 for ( ; *q; q++) {
0362                     if (*q == '\\') {
0363                         if (last_esc) {
0364                             idref += QChar ('\\');
0365                             last_esc = false;
0366                         } else
0367                             last_esc = true;
0368                     } else if (*q == '.' && !last_esc) {
0369                         break;
0370                     } else
0371                         idref += QChar (*q);
0372                 }
0373                 if (!*q)
0374                     idref = vs.mid (p - cval);
0375                 else
0376                     idref = vs.mid (p - cval, q - p);
0377             }
0378             if (*q) {
0379                 ++q;
0380                 if (!idref.isEmpty ()) {
0381                     target = findLocalNodeById (n, idref);
0382                     if (!target)
0383                         q = p;
0384                 }
0385             } else {
0386                 q = p;
0387             }
0388             if (parseTime (vl.mid (q-cval), offset)) {
0389                 dur = Runtime::DurStart;
0390             } else if (*q && !strncmp (q, "end", 3)) {
0391                 dur = Runtime::DurEnd;
0392                 parseTime (vl.mid (q + 3 - cval), offset);
0393             } else if (*q && !strncmp (q, "begin", 5)) {
0394                 dur = Runtime::DurStart;
0395                 parseTime (vl.mid (q + 5 - cval), offset);
0396             } else if (*q && !strncmp (q, "activateevent", 13)) {
0397                 dur = Runtime::DurActivated;
0398                 parseTime (vl.mid (q + 13 - cval), offset);
0399             } else if (*q && !strncmp (q, "inboundsevent", 13)) {
0400                 dur = Runtime::DurInBounds;
0401                 parseTime (vl.mid (q + 13 - cval), offset);
0402             } else if (*q && !strncmp (q, "outofboundsevent", 16)) {
0403                 dur = Runtime::DurOutBounds;
0404                 parseTime (vl.mid (q + 16 - cval), offset);
0405             } else if (*q && !strncmp (q, "statechange", 11)) {
0406                 int op = vl.indexOf ('(', 11);
0407                 if (op > -1) {
0408                     int cp = vl.indexOf (')', op + 1);
0409                     if (cp > -1) {
0410                         payload = evaluateExpr(vl.mid(op + 1, cp - op - 1).toUtf8(), "data");
0411                         dur = Runtime::DurStateChanged;
0412                     }
0413                 }
0414             } else if (*q && !strncmp (q, "accesskey", 9)) {
0415                 int op = vl.indexOf ('(', 9);
0416                 if (op > -1) {
0417                     int cp = vl.indexOf (')', op + 1);
0418                     if (cp > -1) {
0419                         QString ch = vl.mid (op + 1, cp - op - 1);
0420                         if (!ch.isEmpty ()) {
0421                             payload = new KeyLoad (ch[0].unicode ());
0422                             dur = Runtime::DurAccessKey;
0423                             target = n->document ();
0424                         }
0425                     }
0426                 }
0427             } else
0428                 kWarning () << "setDuration no match " << cval;
0429             if (!target &&
0430                    dur >= Runtime::DurActivated && dur <= Runtime::DurOutBounds)
0431                 target = n;
0432             if (target && dur != Runtime::DurTimer)
0433                 itm->connection.connect (target, (MessageType)dur, n, payload);
0434         }
0435     }
0436     itm->durval = (Runtime::Duration) dur;
0437     itm->offset = offset;
0438     itm->payload = payload;
0439 }
0440 
0441 static
0442 void setDurationItems (Node *n, const QString &s, Runtime::DurationItem *item) {
0443     item->clear ();
0444     Runtime::DurationItem *last = item;
0445     QStringList list = s.split (QChar (';'));
0446     bool timer_set = false;
0447     for (int i = 0; i < list.count(); ++i) {
0448         QString val = list[i].trimmed();
0449         if (!val.isEmpty ()) {
0450             Runtime::DurationItem di;
0451             setDurationItem (n, val, &di);
0452             switch (di.durval) {
0453             case Runtime::DurTimer:
0454             case Runtime::DurIndefinite:
0455             case Runtime::DurMedia:
0456                 *item = di;
0457                 timer_set = true;
0458                 break;
0459             default:
0460                 last = last->next = new Runtime::DurationItem;
0461                 *last = di;
0462             }
0463         }
0464     }
0465     if (item->next && !timer_set)
0466         item->durval = Runtime::DurIndefinite;
0467 }
0468 
0469 static bool disabledByExpr (Runtime *rt) {
0470     bool b = false;
0471     if (!rt->expr.isEmpty ()) {
0472         Expression* res = evaluateExpr(rt->expr.toUtf8(), "data");
0473         if (res) {
0474             SMIL::Smil *smil = SMIL::Smil::findSmilNode (rt->element);
0475             res->setRoot (smil ? smil->state_node.ptr() : NULL);
0476             b = !res->toBool ();
0477             delete res;
0478         }
0479     }
0480     return b;
0481 }
0482 
0483 /**
0484  * start, or restart in case of re-use, the durations
0485  */
0486 KDE_NO_EXPORT void Runtime::start () {
0487     if (begin_timer || duration_timer)
0488         element->init ();
0489     timingstate = timings_began;
0490 
0491     int offset = 0;
0492     bool stop = true;
0493     for (DurationItem *dur = durations + (int)BeginTime; dur; dur = dur->next)
0494         switch (dur->durval) {
0495         case DurStart: { // check started/finished
0496             Node *sender = dur->connection.signaler ();
0497             if (sender && sender->state >= Node::state_began) {
0498                 offset = dur->offset;
0499                 Runtime *rt = (Runtime*)sender->role (RoleTiming);
0500                 if (rt)
0501                     offset -= element->document()->last_event_time/10 - rt->start_time;
0502                 stop = false;
0503                 kWarning() << "start trigger on started element";
0504             } // else wait for start event
0505             break;
0506         }
0507         case DurEnd: { // check finished
0508             Node *sender = dur->connection.signaler ();
0509             if (sender && sender->state >= Node::state_finished) {
0510                 int offset = dur->offset;
0511                 Runtime *rt = (Runtime*)sender->role (RoleTiming);
0512                 if (rt)
0513                     offset -= element->document()->last_event_time/10 - rt->finish_time;
0514                 stop = false;
0515                 kWarning() << "start trigger on finished element";
0516             } // else wait for end event
0517             break;
0518         }
0519         case DurTimer:
0520             offset = dur->offset;
0521             stop = false;
0522             break;
0523         default:
0524             break;
0525     }
0526     if (stop)   // wait for event
0527         tryFinish ();
0528     else if (offset > 0)               // start timer
0529         begin_timer = element->document ()->post (element,
0530                 new TimerPosting (10 * offset, begin_timer_id));
0531     else                               // start now
0532         propagateStart ();
0533 }
0534 
0535 KDE_NO_EXPORT void Runtime::finish () {
0536     if (started () || timingstate == timings_began) {
0537         doFinish (); // reschedule through Runtime::stopped
0538     } else {
0539         finish_time = element->document ()->last_event_time/10;
0540         repeat_count = repeat;
0541         NodePtrW guard = element;
0542         element->Node::finish ();
0543         if (guard && element->document ()->active ()) { // check for reset
0544             Posting event (element, MsgEventStopped);
0545             element->deliver (MsgEventStopped, &event);
0546         }
0547     }
0548 }
0549 
0550 KDE_NO_EXPORT void Runtime::startAndBeginNode () {
0551     if (begin_timer || duration_timer)
0552         element->init ();
0553     timingstate = timings_began;
0554     propagateStart ();
0555 }
0556 
0557 KDE_NO_EXPORT
0558 bool Runtime::parseParam (const TrieString & name, const QString & val) {
0559     if (name == Ids::attr_begin) {
0560         setDurationItems (element, val, durations + (int) BeginTime);
0561         if ((timingstate == timings_began && !begin_timer) ||
0562                 timingstate >= timings_stopped) {
0563             if (beginTime ().offset > 0) { // create a timer for start
0564                 if (begin_timer) {
0565                     element->document ()->cancelPosting (begin_timer);
0566                     begin_timer = NULL;
0567                 }
0568                 if (beginTime ().durval == DurTimer)
0569                     begin_timer = element->document ()->post (element,
0570                             new TimerPosting (10 * beginTime ().offset, begin_timer_id));
0571             } else {                              // start now
0572                 propagateStart ();
0573             }
0574         }
0575     } else if (name == Ids::attr_dur) {
0576         setDurationItems (element, val, durations + (int) DurTime);
0577     } else if (name == Ids::attr_end) {
0578         setDurationItems (element, val, durations + (int) EndTime);
0579     } else if (name.startsWith (Ids::attr_fill)) {
0580         Fill * f = &fill;
0581         if (name != Ids::attr_fill) {
0582             f = &fill_def;
0583             *f = fill_inherit;
0584         } else
0585             *f = fill_default;
0586         fill_active = fill_auto;
0587         if (val == "freeze")
0588             *f = fill_freeze;
0589         else if (val == "hold")
0590             *f = fill_hold;
0591         else if (val == "auto")
0592             *f = fill_auto;
0593         else if (val == "remove")
0594             *f = fill_remove;
0595         else if (val == "transition")
0596             *f = fill_transition;
0597         if (fill == fill_default) {
0598             if (fill_def == fill_inherit)
0599                 fill_active = getDefaultFill (element);
0600             else
0601                 fill_active = fill_def;
0602         } else
0603             fill_active = fill;
0604     } else if (name == Ids::attr_title) {
0605         Mrl *mrl = element->mrl ();
0606         if (mrl)
0607             mrl->title = val;
0608     } else if (name == "endsync") {
0609         if ((durTime ().durval == DurMedia || durTime ().durval == 0) &&
0610                 endTime ().durval == DurMedia) {
0611             Node *e = findLocalNodeById (element, val);
0612             if (e) {
0613                 durations [(int) EndTime].connection.connect (
0614                     e, MsgEventStopped, element);
0615                 durations [(int) EndTime].durval = (Duration) MsgEventStopped;
0616             }
0617         }
0618     } else if (name.startsWith ("repeat")) {
0619         if (val.indexOf ("indefinite") > -1)
0620             repeat = repeat_count = DurIndefinite;
0621         else
0622             repeat = repeat_count = val.toInt ();
0623     } else if (name.startsWith ("expr")) {
0624         expr = val;
0625     } else // TODO restart/restartDefault
0626         return false;
0627     return true;
0628 }
0629 
0630 KDE_NO_EXPORT void Runtime::message (MessageType msg, void *content) {
0631     switch (msg) {
0632         case MsgEventTimer: {
0633             TimerPosting *te = static_cast <TimerPosting *> (content);
0634             if (te->event_id == begin_timer_id) {
0635                 begin_timer = NULL;
0636                 propagateStart ();
0637             } else if (te->event_id == dur_timer_id) {
0638                 duration_timer = NULL;
0639                 doFinish ();
0640             } else {
0641                 kWarning () << "unhandled timer event";
0642             }
0643             return;
0644         }
0645         case MsgEventStarted: {
0646             Posting *event = static_cast <Posting *> (content);
0647             if (event->source.ptr () == element) {
0648                 started_timer = NULL;
0649                 start_time = element->document ()->last_event_time/10;
0650                 setDuration ();
0651                 NodePtrW guard = element;
0652                 element->deliver (MsgEventStarted, event);
0653                 if (guard) {
0654                     element->begin ();
0655                     if (!element->document ()->postponed ())
0656                         tryFinish ();
0657                 }
0658                 return;
0659             }
0660             break;
0661         }
0662         case MsgEventStopped: {
0663             Posting *event = static_cast <Posting *> (content);
0664             if (event->source.ptr () == element) {
0665                 stopped_timer = NULL;
0666                 stopped ();
0667                 return;
0668             }
0669             break;
0670         }
0671         default:
0672             break;
0673     }
0674     if ((int) msg >= (int) DurLastDuration)
0675         return;
0676 
0677     Posting *event = static_cast <Posting *> (content);
0678     for (DurationItem *dur = beginTime ().next; dur; dur = dur->next) {
0679         if (dur->matches ((Duration) msg, event)) {
0680             if (started ())
0681                 element->message (MsgStateRewind);
0682             else
0683                 element->activate ();
0684             if (element && dur->offset > 0) {
0685                 if (begin_timer)
0686                     element->document ()->cancelPosting (begin_timer);
0687                 begin_timer = element->document ()->post (element,
0688                         new TimerPosting(10 * dur->offset, begin_timer_id));
0689             } else { //FIXME neg. offsets
0690                 propagateStart ();
0691             }
0692             if (element->state == Node::state_finished)
0693                 element->state = Node::state_activated;//rewind to activated
0694             return;
0695         }
0696     }
0697     if (started ()) {
0698         Posting *event = static_cast <Posting *> (content);
0699         for (DurationItem *dur = endTime ().next; dur; dur = dur->next)
0700             if (dur->matches ((Duration) msg, event)) {
0701                 if (element && dur->offset > 0) {
0702                     if (duration_timer)
0703                         element->document ()->cancelPosting (duration_timer);
0704                     duration_timer = element->document ()->post (element,
0705                             new TimerPosting (10 * dur->offset, dur_timer_id));
0706                 } else {
0707                     doFinish ();
0708                 }
0709                 break;
0710             }
0711     }
0712 }
0713 
0714 KDE_NO_EXPORT void *Runtime::role (RoleType msg, void *content) {
0715     switch (msg) {
0716     case RoleReceivers: {
0717         switch ((MessageType) (long) content) {
0718         case MsgEventStopped:
0719             return &m_StoppedListeners;
0720         case MsgEventStarted:
0721             return &m_StartedListeners;
0722         case MsgEventStarting:
0723             return &m_StartListeners;
0724         case MsgChildTransformedIn:
0725             break;
0726         default:
0727             kWarning () << "unknown event requested " << (int)msg;
0728         }
0729         return NULL;
0730     }
0731     default:
0732         break;
0733     }
0734     return MsgUnhandled;
0735 }
0736 
0737 KDE_NO_EXPORT void Runtime::propagateStop (bool forced) {
0738     if (state() == TimingsInit || state() >= timings_stopped)
0739         return; // nothing to stop
0740     if (!forced) {
0741         if ((durTime ().durval == DurMedia ||
0742                     durTime ().durval == DurTransition ) &&
0743                 endTime ().durval == DurMedia)
0744             return; // wait for external eof
0745         if (endTime ().durval != DurTimer && endTime ().durval != DurMedia &&
0746                 (started () || beginTime().durval == DurTimer))
0747             return; // wait for event
0748         if (durTime ().durval == DurIndefinite)
0749             return; // this may take a while :-)
0750         if (duration_timer)
0751             return; // timerEvent will call us with forced=true
0752         // bail out if a child still running
0753         for (Node *c = element->firstChild (); c; c = c->nextSibling ())
0754             if (c->unfinished () || Node::state_deferred == c->state)
0755                 return; // a child still running
0756     }
0757     bool was_started (started ());
0758     timingstate = timings_freezed;
0759     if (begin_timer) {
0760         element->document ()->cancelPosting (begin_timer);
0761         begin_timer = NULL;
0762     }
0763     if (duration_timer) {
0764         element->document ()->cancelPosting (duration_timer);
0765         duration_timer = NULL;
0766     }
0767     if (was_started && element->document ()->active ())
0768         stopped_timer = element->document()->post (
0769                 element, new Posting (element, MsgEventStopped));
0770     else if (element->unfinished ())
0771         element->finish ();
0772 }
0773 
0774 KDE_NO_EXPORT void Runtime::propagateStart () {
0775     if (begin_timer) {
0776         element->document ()->cancelPosting (begin_timer);
0777         begin_timer = NULL;
0778     }
0779     if (disabledByExpr (this)) {
0780         if (timings_freezed == timingstate)
0781             element->message (MsgStateFreeze);
0782         timingstate = TimingsDisabled;
0783         return;
0784     }
0785     timingstate = trans_in_dur ? TimingsTransIn : timings_started;
0786     element->deliver (MsgEventStarting, element);
0787     started_timer = element->document()->post (
0788             element, new Posting (element, MsgEventStarted));
0789 }
0790 
0791 /**
0792  * begin_timer timer expired
0793  */
0794 KDE_NO_EXPORT void Runtime::setDuration () {
0795     if (begin_timer) {
0796         element->document ()->cancelPosting (begin_timer);
0797         begin_timer = NULL;
0798     }
0799     if (duration_timer) {
0800         element->document ()->cancelPosting (duration_timer);
0801         duration_timer = NULL;
0802     }
0803     int duration = 0;
0804     if (durTime ().durval == DurTimer) {
0805         duration = durTime ().offset;
0806         if (endTime ().durval == DurTimer &&
0807                 (!duration || endTime().offset - beginTime().offset < duration))
0808             duration = endTime ().offset - beginTime ().offset;
0809     } else if (endTime ().durval == DurTimer) {
0810         duration = endTime ().offset;
0811     }
0812     if (duration > 0)
0813         duration_timer = element->document ()->post (element,
0814                 new TimerPosting (10 * duration, dur_timer_id));
0815 }
0816 
0817 bool Runtime::started () const {
0818     return timingstate >= timings_started && timingstate < timings_stopped;
0819 }
0820 
0821 static bool runtimeBegan (Runtime *r) {
0822     return r->timingstate >= Runtime::timings_began &&
0823         r->timingstate < Runtime::timings_stopped;
0824 }
0825 
0826 /**
0827  * duration_timer timer expired or no duration set after started
0828  */
0829 KDE_NO_EXPORT void Runtime::stopped () {
0830     if (element->active ()) {
0831         if (repeat_count == DurIndefinite || 0 < --repeat_count) {
0832             element->message (MsgStateRewind);
0833             beginTime ().offset  = 0;
0834             beginTime ().durval = DurTimer;
0835             if (begin_timer)
0836                 element->document ()->cancelPosting (begin_timer);
0837             propagateStart ();
0838         } else {
0839             repeat_count = repeat;
0840             element->finish ();
0841         }
0842     }
0843 }
0844 
0845 //-----------------------------------------------------------------------------
0846 
0847 KDE_NO_CDTOR_EXPORT SizeType::SizeType () {
0848     reset ();
0849 }
0850 
0851 KDE_NO_CDTOR_EXPORT SizeType::SizeType (const QString & s, bool perc)
0852  : perc_size (perc ? -100 : 0) {
0853     *this = s;
0854 }
0855 
0856 void SizeType::reset () {
0857     perc_size = 0;
0858     abs_size = 0;
0859     isset = false;
0860     has_percentage = false;
0861 }
0862 
0863 SizeType & SizeType::operator = (const QString & s) {
0864     QString strval (s);
0865     int p = strval.indexOf (QChar ('%'));
0866     if (p > -1) {
0867         strval.truncate (p);
0868         has_percentage = true;
0869     }
0870     int px = strval.indexOf (QChar ('p')); // strip px
0871     if (px > -1)
0872         strval.truncate (px);
0873     double d = strval.toDouble (&isset);
0874     if (isset) {
0875         if (p > -1)
0876             perc_size = d;
0877         else if (perc_size < 0)
0878             perc_size = 100 * d;
0879         else
0880             abs_size = d;
0881     }
0882     return *this;
0883 }
0884 
0885 SizeType & SizeType::operator = (Single d) {
0886     reset ();
0887     abs_size = d;
0888     return *this;
0889 }
0890 
0891 SizeType & SizeType::operator += (const SizeType & s) {
0892     perc_size += s.perc_size;
0893     abs_size += s.abs_size;
0894     return *this;
0895 }
0896 
0897 SizeType & SizeType::operator -= (const SizeType & s) {
0898     perc_size -= s.perc_size;
0899     abs_size -= s.abs_size;
0900     return *this;
0901 }
0902 
0903 Single SizeType::size (Single relative_to) const {
0904     Single s = abs_size;
0905     s += perc_size * relative_to / 100;
0906     return s;
0907 }
0908 
0909 QString SizeType::toString () const {
0910     if (isset) {
0911         if (has_percentage)
0912             return QString ("%1%").arg ((int) size (100));
0913         return QString::number ((double) size (100));
0914     }
0915     return QString ();
0916 }
0917 
0918 //-----------------%<----------------------------------------------------------
0919 
0920 template<>
0921 IRect IRect::intersect (const IRect & r) const {
0922     int a (point.x < r.point.x ? r.point.x : point.x);
0923     int b (point.y < r.point.y ? r.point.y : point.y);
0924     return IRect (a, b,
0925             ((point.x + size.width < r.point.x + r.size.width)
0926              ? point.x + size.width : r.point.x + r.size.width) - a,
0927             ((point.y + size.height < r.point.y + r.size.height)
0928              ? point.y + size.height : r.point.y + r.size.height) - b);
0929 }
0930 
0931 //-----------------------------------------------------------------------------
0932 
0933 KDE_NO_EXPORT void CalculatedSizer::resetSizes () {
0934     left.reset ();
0935     top.reset ();
0936     width.reset ();
0937     height.reset ();
0938     right.reset ();
0939     bottom.reset ();
0940     reg_point.truncate (0);
0941     reg_align = QString::fromLatin1 ("topLeft");
0942 }
0943 
0944 static bool regPoints (const QString & str, Single & x, Single & y) {
0945     QByteArray ba = str.toLower ().toLatin1 ();
0946     const char *rp = ba.constData ();
0947     if (!rp)
0948         return false;
0949     if (!strcmp (rp, "center")) {
0950         x = 50;
0951         y = 50;
0952     } else {
0953         if (!strncmp (rp, "top", 3)) {
0954             y = 0;
0955             rp += 3;
0956         } else if (!strncmp (rp, "mid", 3)) {
0957             y = 50;
0958             rp += 3;
0959         } else if (!strncmp (rp, "bottom", 6)) {
0960             y = 100;
0961             rp += 6;
0962         } else
0963             return false;
0964         if (!strcmp (rp, "left")) {
0965             x = 0;
0966         } else if (!strcmp (rp, "mid")) {
0967             x = 50;
0968         } else if (!strcmp (rp, "right")) {
0969             x = 100;
0970         } else
0971             return false;
0972     }
0973     return true;
0974 }
0975 
0976 KDE_NO_EXPORT
0977 bool CalculatedSizer::applyRegPoints (Node * node,
0978         CalculatedSizer *region_sizes, Single w, Single h,
0979         Single & xoff, Single & yoff, Single & w1, Single & h1) {
0980     QString rp = reg_point;
0981     if (rp.isEmpty () && region_sizes)
0982         rp = region_sizes->reg_point;
0983     if (rp.isEmpty ())
0984         return false;
0985     Single rpx, rpy, rax, ray;
0986     if (!regPoints (rp, rpx, rpy)) {
0987         node = SMIL::Smil::findSmilNode (node);
0988         if (!node)
0989             return false;
0990         node = static_cast <SMIL::Smil *> (node)->layout_node.ptr ();
0991         if (!node)
0992             return false;
0993         Node *c = node->firstChild ();
0994         for (; c; c = c->nextSibling ())
0995             if (c->id == SMIL::id_node_regpoint &&
0996                     static_cast<Element*>(c)->getAttribute (Ids::attr_id)
0997                         == rp) {
0998                 Single i1, i2; // dummies
0999                 SMIL::RegPoint *rp_elm = static_cast <SMIL::RegPoint *> (c);
1000                 rp_elm->sizes.calcSizes (0L, NULL, 100, 100, rpx, rpy, i1, i2);
1001                 QString ra = rp_elm->getAttribute ("regAlign");
1002                 if (!ra.isEmpty () && reg_align.isEmpty ())
1003                     reg_align = ra;
1004                 break;
1005             }
1006         if (!c)
1007             return false; // not found
1008     }
1009     QString ra = reg_align;
1010     if (ra.isEmpty () && region_sizes)
1011         ra = region_sizes->reg_align;
1012     if (!regPoints (ra, rax, ray))
1013         rax = ray = 0; // default back to topLeft
1014     if (!(int)w1 || !(int)h1) {
1015         xoff = w * (rpx - rax) / 100;
1016         yoff = h * (rpy - ray) / 100;
1017         w1 = w - w * (rpx > rax ? (rpx - rax) : (rax - rpx)) / 100;
1018         h1 = h - h * (rpy > ray ? (rpy - ray) : (ray - rpy)) / 100;
1019     } else {
1020         xoff = (w * rpx - w1 * rax) / 100;
1021         yoff = (h * rpy - h1 * ray) / 100;
1022     }
1023     return true; // success getting sizes based on regPoint
1024 }
1025 
1026 KDE_NO_EXPORT void CalculatedSizer::calcSizes (Node * node,
1027         CalculatedSizer *region_sz, Single w, Single h,
1028         Single & xoff, Single & yoff, Single & w1, Single & h1) {
1029     if (region_sz && applyRegPoints (node, region_sz, w, h, xoff, yoff, w1, h1))
1030         return;
1031     if (left.isSet ())
1032         xoff = left.size (w);
1033     else if (width.isSet ()) {
1034         if (right.isSet ())
1035             xoff = w - width.size (w) - right.size (w);
1036         else
1037             xoff = 0;
1038     } else
1039         xoff = 0;
1040     if (top.isSet ())
1041         yoff = top.size (h);
1042     else if (height.isSet ()) {
1043         if (bottom.isSet ())
1044             yoff = h - height.size (h) - bottom.size (h);
1045         else
1046             yoff = 0;
1047     } else
1048         yoff = 0;
1049     if (width.isSet ())
1050         w1 = width.size (w);
1051     else if (right.isSet ())
1052         w1 = w - xoff - right.size (w);
1053     else
1054         w1 = w - xoff;
1055     if (w1 < 0)
1056         w1 = 0;
1057     if (height.isSet ())
1058         h1 = height.size (h);
1059     else if (bottom.isSet ())
1060         h1 = h - yoff - bottom.size (h);
1061     else
1062         h1 = h - yoff;
1063     if (h1 < 0)
1064         h1 = 0;
1065 }
1066 
1067 KDE_NO_EXPORT
1068 bool CalculatedSizer::setSizeParam(const TrieString &name, const QString &val) {
1069     if (name == Ids::attr_left) {
1070         left = val;
1071     } else if (name == Ids::attr_top) {
1072         top = val;
1073     } else if (name == Ids::attr_width) {
1074         width = val;
1075     } else if (name == Ids::attr_height) {
1076         height = val;
1077     } else if (name == Ids::attr_right) {
1078         right = val;
1079     } else if (name == Ids::attr_bottom) {
1080         bottom = val;
1081     } else if (name == "regPoint") {
1082         reg_point = val;
1083     } else if (name == "regAlign") {
1084         reg_align = val;
1085     } else if (name == "mediaAlign") {
1086         reg_point = val;
1087         reg_align = val;
1088     } else
1089         return false;
1090     return true;
1091 }
1092 
1093 KDE_NO_EXPORT void
1094 CalculatedSizer::move (const SizeType &x, const SizeType &y) {
1095     if (left.isSet ()) {
1096         if (right.isSet ()) {
1097             right += x;
1098             right -= left;
1099         }
1100         left = x;
1101     } else if (right.isSet ()) {
1102         right = x;
1103     } else {
1104         left = x;
1105     }
1106     if (top.isSet ()) {
1107         if (bottom.isSet ()) {
1108             bottom += y;
1109             bottom -= top;
1110         }
1111         top = y;
1112     } else if (bottom.isSet ()) {
1113             bottom = y;
1114     } else {
1115         top = y;
1116     }
1117 }
1118 
1119 //-----------------------------------------------------------------------------
1120 
1121 KDE_NO_CDTOR_EXPORT MouseListeners::MouseListeners () {}
1122 
1123 ConnectionList *MouseListeners::receivers (MessageType eid) {
1124     switch (eid) {
1125         case MsgEventClicked:
1126             return &m_ActionListeners;
1127         case MsgEventPointerInBounds:
1128             return &m_InBoundsListeners;
1129         case MsgEventPointerOutBounds:
1130             return &m_OutOfBoundsListeners;
1131         default:
1132             break;
1133     }
1134     return NULL;
1135 }
1136 
1137 //-----------------------------------------------------------------------------
1138 
1139 static Element * fromScheduleGroup (NodePtr & d, const QString & tag) {
1140     QByteArray ba = tag.toLatin1 ();
1141     const char *ctag = ba.constData ();
1142     if (!strcmp (ctag, "par"))
1143         return new SMIL::Par (d);
1144     else if (!strcmp (ctag, "seq"))
1145         return new SMIL::Seq (d);
1146     else if (!strcmp (ctag, "excl"))
1147         return new SMIL::Excl (d);
1148     return NULL;
1149 }
1150 
1151 static Element * fromParamGroup (NodePtr & d, const QString & tag) {
1152     QByteArray ba = tag.toLatin1 ();
1153     const char *ctag = ba.constData ();
1154     if (!strcmp (ctag, "param"))
1155         return new SMIL::Param (d);
1156     else if (!strcmp (ctag, "area") || !strcmp (ctag, "anchor"))
1157         return new SMIL::Area (d, tag);
1158     return NULL;
1159 }
1160 
1161 static Element * fromAnimateGroup (NodePtr & d, const QString & tag) {
1162     QByteArray ba = tag.toLatin1 ();
1163     const char *ctag = ba.constData ();
1164     if (!strcmp (ctag, "set"))
1165         return new SMIL::Set (d);
1166     else if (!strcmp (ctag, "animate"))
1167         return new SMIL::Animate (d);
1168     else if (!strcmp (ctag, "animateColor"))
1169         return new SMIL::AnimateColor (d);
1170     else if (!strcmp (ctag, "animateMotion"))
1171         return new SMIL::AnimateMotion (d);
1172     else if (!strcmp (ctag, "newvalue"))
1173         return new SMIL::NewValue (d);
1174     else if (!strcmp (ctag, "setvalue"))
1175         return new SMIL::SetValue (d);
1176     else if (!strcmp (ctag, "delvalue"))
1177         return new SMIL::DelValue (d);
1178     else if (!strcmp (ctag, "send"))
1179         return new SMIL::Send (d);
1180     return NULL;
1181 }
1182 
1183 static Element * fromMediaContentGroup (NodePtr & d, const QString & tag) {
1184     QByteArray ba = tag.toLatin1 ();
1185     const char *taglatin = ba.constData ();
1186     if (!strcmp (taglatin, "video") ||
1187             !strcmp (taglatin, "audio") ||
1188             !strcmp (taglatin, "img") ||
1189             !strcmp (taglatin, "animation") ||
1190             !strcmp (taglatin, "textstream") ||
1191             !strcmp (taglatin, "ref"))
1192         return new SMIL::RefMediaType (d, ba);
1193     else if (!strcmp (taglatin, "text"))
1194         return new SMIL::TextMediaType (d);
1195     else if (!strcmp (taglatin, "brush"))
1196         return new SMIL::Brush (d);
1197     else if (!strcmp (taglatin, "a"))
1198         return new SMIL::Anchor (d);
1199     else if (!strcmp (taglatin, "smilText"))
1200         return new SMIL::SmilText (d);
1201     // animation, textstream
1202     return NULL;
1203 }
1204 
1205 static Element * fromContentControlGroup (NodePtr & d, const QString & tag) {
1206     if (!strcmp (tag.toLatin1 ().constData (), "switch"))
1207         return new SMIL::Switch (d);
1208     return NULL;
1209 }
1210 
1211 static Element *fromTextFlowGroup (NodePtr &d, const QString &tag) {
1212     QByteArray ba = tag.toLatin1 ();
1213     const char *taglatin = ba.constData ();
1214     if (!strcmp (taglatin, "div"))
1215         return new SMIL::TextFlow (d, SMIL::id_node_div, tag.toUtf8 ());
1216     if (!strcmp (taglatin, "span"))
1217         return new SMIL::TextFlow (d, SMIL::id_node_span, tag.toUtf8 ());
1218     if (!strcmp (taglatin, "p"))
1219         return new SMIL::TextFlow (d, SMIL::id_node_p, tag.toUtf8 ());
1220     if (!strcmp (taglatin, "br"))
1221         return new SMIL::TextFlow (d, SMIL::id_node_br, tag.toUtf8 ());
1222     return NULL;
1223 }
1224 
1225 static unsigned int setRGBA (unsigned int color, int opacity) {
1226     int a = ((color >> 24) & 0xff) * opacity / 100;
1227     return (a << 24) | (color & 0xffffff);
1228 }
1229 
1230 void SmilColorProperty::init ()
1231 {
1232     color = 0;
1233     opacity = 100;
1234 }
1235 
1236 static unsigned int rgbFromValue (const QString& val) {
1237     SmilColorProperty p;
1238     p.init();
1239     p.setColor (val);
1240     return 0xffffff & p.color;
1241 }
1242 
1243 void SmilColorProperty::setColor (const QString &val)
1244 {
1245     if (val.isEmpty () || val == "transparent")
1246         color = 0;
1247     else if (val.startsWith (QChar ('#')) && val.length() == 9)
1248         color = val.mid (1).toUInt (NULL, 16);
1249     else
1250         color = setRGBA (QColor (val).rgba (), opacity);
1251 }
1252 
1253 void SmilColorProperty::setOpacity (const QString &val)
1254 {
1255     opacity = SizeType (val, true).size (100);
1256     color = setRGBA (color, opacity);
1257 }
1258 
1259 static bool parseBackgroundParam (SmilColorProperty &p, const TrieString &name, const QString &val)
1260 {
1261     if (name == "background-color" || name == "backgroundColor")
1262         p.setColor (val);
1263     else if (name == "backgroundOpacity")
1264         p.setOpacity (val);
1265     else
1266         return false;
1267     return true;
1268 }
1269 
1270 void MediaOpacity::init () {
1271     bg_opacity = opacity = 100;
1272 }
1273 
1274 static bool parseMediaOpacityParam (MediaOpacity &p, const TrieString &name, const QString &val) {
1275     if (name == "mediaOpacity")
1276         p.opacity = (int) SizeType (val, true).size (100);
1277     else if (name == "mediaBackgroundOpacity")
1278         p.bg_opacity = (int) SizeType (val, true).size (100);
1279     else
1280         return false;
1281     return true;
1282 }
1283 
1284 void TransitionModule::init () {
1285     trans_out_active = false;
1286     trans_start_time = 0;
1287 }
1288 
1289 void TransitionModule::cancelTimer (Node *n) {
1290     if (trans_out_timer) {
1291         n->document ()->cancelPosting (trans_out_timer);
1292         trans_out_timer = NULL;
1293     }
1294 }
1295 
1296 void TransitionModule::begin (Node *n, Runtime *runtime)
1297 {
1298     SMIL::Transition *trans = convertNode <SMIL::Transition> (trans_in);
1299     if (trans && trans->supported ()) {
1300         active_trans = trans_in;
1301         runtime->timingstate = Runtime::TimingsTransIn;
1302         trans_gain = 0.0;
1303         transition_updater.connect (n->document (), MsgSurfaceUpdate, n);
1304         trans_start_time = n->document ()->last_event_time;
1305         trans_end_time = trans_start_time + 10 * trans->dur;
1306         if (Runtime::DurTimer == runtime->durTime ().durval &&
1307                 0 == runtime->durTime ().offset &&
1308                 Runtime::DurMedia == runtime->endTime ().durval)
1309             runtime->durTime ().durval = Runtime::DurTransition;
1310     }
1311     if (Runtime::DurTimer == runtime->durTime().durval &&
1312             runtime->durTime().offset > 0) {
1313         // FIXME: also account for fill duration
1314         trans = convertNode <SMIL::Transition> (trans_out);
1315         if (trans && trans->supported () &&
1316                 (int) trans->dur < runtime->durTime().offset)
1317             trans_out_timer = n->document()->post (n,
1318                     new TimerPosting ((runtime->durTime().offset - trans->dur) * 10,
1319                         trans_out_timer_id));
1320     }
1321 }
1322 
1323 bool TransitionModule::handleMessage (Node *n, Runtime *runtime, Surface *s,
1324         MessageType msg, void *content) {
1325     switch (msg) {
1326     case MsgSurfaceUpdate: {
1327         UpdateEvent *ue = static_cast <UpdateEvent *> (content);
1328 
1329         trans_start_time += ue->skipped_time;
1330         trans_end_time += ue->skipped_time;
1331 
1332         trans_gain = 1.0 * (ue->cur_event_time - trans_start_time) /
1333             (trans_end_time - trans_start_time);
1334         if (trans_gain > 0.9999) {
1335             transition_updater.disconnect ();
1336             if (active_trans == trans_in) {
1337                 runtime->timingstate = Runtime::timings_started;
1338                 n->deliver (MsgChildTransformedIn, n);
1339             }
1340             if (!trans_out_active)
1341                 active_trans = NULL;
1342             trans_gain = 1.0;
1343             if (Runtime::DurTransition == runtime->durTime ().durval) {
1344                 runtime->durTime ().durval = Runtime::DurTimer;
1345                 runtime->tryFinish ();
1346             }
1347         }
1348         if (s && s->parentNode())
1349             s->parentNode()->repaint (s->bounds);
1350         return true;
1351     }
1352 
1353     case MsgEventTimer: {
1354         TimerPosting *te = static_cast <TimerPosting *> (content);
1355         if (te->event_id == trans_out_timer_id) {
1356             if (active_trans)
1357                 transition_updater.disconnect ();
1358             trans_out_timer = NULL;
1359             active_trans = trans_out;
1360             SMIL::Transition *trans = convertNode<SMIL::Transition> (trans_out);
1361             if (trans) {
1362                 trans_gain = 0.0;
1363                 transition_updater.connect (n->document(), MsgSurfaceUpdate, n);
1364                 trans_start_time = n->document ()->last_event_time;
1365                 trans_end_time = trans_start_time + 10 * trans->dur;
1366                 trans_out_active = true;
1367                 if (s)
1368                     s->repaint ();
1369             }
1370             return true;
1371         }
1372         break;
1373     }
1374     default:
1375         break;
1376     }
1377     return false;
1378 }
1379 
1380 void TransitionModule::finish (Node *n) {
1381     transition_updater.disconnect ();
1382     cancelTimer (n);
1383 }
1384 
1385 //-----------------------------------------------------------------------------
1386 
1387 KDE_NO_EXPORT Node *SMIL::Smil::childFromTag (const QString & tag) {
1388     QByteArray ba = tag.toLatin1 ();
1389     const char *ctag = ba.constData ();
1390     if (!strcmp (ctag, "body"))
1391         return new SMIL::Body (m_doc);
1392     else if (!strcmp (ctag, "head"))
1393         return new SMIL::Head (m_doc);
1394     return NULL;
1395 }
1396 
1397 KDE_NO_EXPORT void SMIL::Smil::activate () {
1398     resolved = true;
1399     if (layout_node)
1400         Element::activate ();
1401     else
1402         Element::deactivate(); // some unfortunate reset in parent doc
1403 }
1404 
1405 KDE_NO_EXPORT void SMIL::Smil::deactivate () {
1406     Mrl::deactivate ();
1407 }
1408 
1409 KDE_NO_EXPORT void SMIL::Smil::message (MessageType msg, void *content) {
1410     switch (msg) {
1411 
1412     case MsgChildFinished: {
1413         Posting *post = (Posting *) content;
1414         if (unfinished ()) {
1415             if (post->source->nextSibling ())
1416                 post->source->nextSibling ()->activate ();
1417             else {
1418                 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
1419                     if (e->active ())
1420                         e->deactivate ();
1421                 finish ();
1422             }
1423         }
1424         break;
1425     }
1426 
1427     case MsgSurfaceBoundsUpdate: {
1428         Layout *layout = convertNode <SMIL::Layout> (layout_node);
1429         if (layout && layout->root_layout)
1430             layout->root_layout->message (msg, content);
1431         return;
1432     }
1433 
1434     default:
1435         Mrl::message (msg, content);
1436     }
1437 }
1438 
1439 KDE_NO_EXPORT void SMIL::Smil::closed () {
1440     Node *head = findHeadNode (this);
1441     if (!head) {
1442         head = new SMIL::Head (m_doc);
1443         insertBefore (head, firstChild ());
1444         head->setAuxiliaryNode (true);
1445         head->closed ();
1446     }
1447     for (Node *e = head->firstChild (); e; e = e->nextSibling ()) {
1448         if (e->id == id_node_layout) {
1449             layout_node = e;
1450         } else if (e->id == id_node_title) {
1451             QString str = e->innerText ();
1452             title = str.left (str.indexOf (QChar ('\n')));
1453         } else if (e->id == id_node_state) {
1454             state_node = e;
1455         } else if (e->id == id_node_meta) {
1456             Element *elm = static_cast <Element *> (e);
1457             const QString name = elm->getAttribute (Ids::attr_name);
1458             if (name == QString::fromLatin1 ("title"))
1459                 title = elm->getAttribute ("content");
1460             else if (name == QString::fromLatin1 ("base"))
1461                 src = elm->getAttribute ("content");
1462         }
1463     }
1464     Mrl::closed ();
1465 }
1466 
1467 void *SMIL::Smil::role (RoleType msg, void *content)
1468 {
1469     if (RolePlaylist == msg)
1470         return !title.isEmpty () || //return false if no title and only one
1471             previousSibling () || nextSibling () ? (PlaylistRole *) this : NULL;
1472     return Mrl::role (msg, content);
1473 }
1474 
1475 void SMIL::Smil::jump (const QString & id) {
1476     Node *n = document ()->getElementById (this, id, false);
1477     if (n) {
1478         if (n->unfinished ())
1479             kDebug() << "Smil::jump node is unfinished " << id;
1480         else {
1481             for (Node *p = n; p; p = p->parentNode ()) {
1482                 if (p->unfinished () &&
1483                         p->id >= id_node_first_group &&
1484                         p->id <= id_node_last_group) {
1485                     static_cast <GroupBase *> (p)->setJumpNode (n);
1486                     break;
1487                 }
1488                 if (n->id == id_node_body || n->id == id_node_smil) {
1489                     kError() << "Smil::jump node passed body for " <<id<< endl;
1490                     break;
1491                 }
1492             }
1493         }
1494     }
1495 }
1496 
1497 SMIL::Smil * SMIL::Smil::findSmilNode (Node * node) {
1498     for (Node * e = node; e; e = e->parentNode ())
1499         if (e->id == SMIL::id_node_smil)
1500             return static_cast <SMIL::Smil *> (e);
1501     return 0L;
1502 }
1503 
1504 static QString exprStringValue (Node *node, const QString &str) {
1505     Expression* res = evaluateExpr(str.toUtf8(), "data");
1506     if (res) {
1507         SMIL::Smil *smil = SMIL::Smil::findSmilNode (node);
1508         res->setRoot (smil ? smil->state_node.ptr() : NULL);
1509         QString s = res->toString();
1510         delete res;
1511         return s;
1512     }
1513     return str;
1514 }
1515 
1516 static QString applySubstitution (Node *n, const QString &str, int p, int q) {
1517     QString s = exprStringValue (n, str.mid (p + 1, q - p - 1));
1518     return str.left (p) + s + str.mid (q + 1 );
1519 }
1520 
1521 //-----------------------------------------------------------------------------
1522 
1523 static void headChildDone (Node *node, Node *child) {
1524     if (node->unfinished ()) {
1525         if (child && child->nextSibling ())
1526             child->nextSibling ()->activate ();
1527         else
1528             node->finish (); // we're done
1529     }
1530 }
1531 
1532 KDE_NO_EXPORT Node *SMIL::Head::childFromTag (const QString & tag) {
1533     QByteArray ba = tag.toLatin1 ();
1534     const char *ctag = ba.constData ();
1535     if (!strcmp (ctag, "layout"))
1536         return new SMIL::Layout (m_doc);
1537     else if (!strcmp (ctag, "title"))
1538         return new DarkNode (m_doc, ctag, id_node_title);
1539     else if (!strcmp (ctag, "meta"))
1540         return new DarkNode (m_doc, ctag, id_node_meta);
1541     else if (!strcmp (ctag, "state"))
1542         return new SMIL::State (m_doc);
1543     else if (!strcmp (ctag, "transition"))
1544         return new SMIL::Transition (m_doc);
1545     return NULL;
1546 }
1547 
1548 KDE_NO_EXPORT void SMIL::Head::closed () {
1549     for (Node *e = firstChild (); e; e = e->nextSibling ())
1550         if (e->id == id_node_layout)
1551             return;
1552     SMIL::Layout * layout = new SMIL::Layout (m_doc);
1553     appendChild (layout);
1554     layout->setAuxiliaryNode (true);
1555     layout->closed (); // add root-layout and a region
1556     Element::closed ();
1557 }
1558 
1559 KDE_NO_EXPORT void SMIL::Head::message (MessageType msg, void *content) {
1560     if (MsgChildFinished == msg) {
1561         headChildDone (this, ((Posting *) content)->source.ptr ());
1562         return;
1563     }
1564     Element::message (msg, content);
1565 }
1566 
1567 //-----------------------------------------------------------------------------
1568 
1569 SMIL::State::State (NodePtr &d)
1570  : Element (d, id_node_state), media_info (NULL) {}
1571 
1572 Node *SMIL::State::childFromTag (const QString &tag) {
1573     if (tag == "data")
1574         return new DarkNode (m_doc, tag.toUtf8 (), SMIL::id_node_state_data);
1575     return NULL;
1576 }
1577 
1578 void SMIL::State::closed () {
1579     if (!firstChild ()) {
1580         appendChild (new DarkNode (m_doc, "data", SMIL::id_node_state_data));
1581         firstChild ()->setAuxiliaryNode (true);
1582     }
1583 }
1584 
1585 KDE_NO_EXPORT void SMIL::State::activate () {
1586     init ();
1587     Element::activate ();
1588 }
1589 
1590 KDE_NO_EXPORT
1591 void SMIL::State::parseParam (const TrieString &name, const QString &val) {
1592     if (name == Ids::attr_src) {
1593         Smil *s = val.isEmpty () ? NULL : SMIL::Smil::findSmilNode (this);
1594         if (s) {
1595             m_url.clear ();
1596             if (!media_info)
1597                 media_info = new MediaInfo (this, MediaManager::Text);
1598             Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
1599             QString url = mrl ? KURL (mrl->absolutePath(), val).url() : val;
1600             postpone_lock = document ()->postpone ();
1601             media_info->wget (url, domain ());
1602             m_url = url;
1603         }
1604     } else {
1605         Element::parseParam (name, val);
1606     }
1607 }
1608 
1609 KDE_NO_EXPORT void SMIL::State::deactivate () {
1610     delete media_info;
1611     media_info = NULL;
1612     postpone_lock = NULL;
1613     Element::deactivate ();
1614     m_url.clear ();
1615 }
1616 
1617 QString SMIL::State::domain () {
1618     QString s = m_url;
1619     if (s.isEmpty ()) {
1620         for (Node *p = parentNode (); p; p = p->parentNode ()) {
1621             Mrl *m = p->mrl ();
1622             if (m && !m->src.isEmpty () && m->src != "Playlist://") {
1623                 s = m->absolutePath ();
1624                 break;
1625             }
1626         }
1627     }
1628     KUrl url (s);
1629     if (url.isLocalFile ())
1630         return QString ();
1631     return url.protocol () + "://" + url.host ();
1632 }
1633 
1634 void SMIL::State::stateChanged (Node *ref) {
1635     Connection *c = m_StateChangeListeners.first ();
1636     for (; c; c = m_StateChangeListeners.next ()) {
1637         if (c->payload && c->connecter) {
1638             Expression *expr = (Expression *) c->payload;
1639             expr->setRoot (this);
1640             Expression::iterator it, e = expr->end();
1641             for (it = expr->begin(); it != e; ++it) {
1642                 if (it->node == ref)
1643                     document()->post (c->connecter,
1644                                      new Posting (this, MsgStateChanged, expr));
1645             }
1646         }
1647     }
1648 }
1649 
1650 void SMIL::State::setValue (Node *ref, const QString &value) {
1651     const QString old = ref->nodeValue ();
1652     const QString s = exprStringValue (this, value);
1653     ref->clearChildren ();
1654     if (!s.isEmpty ())
1655         ref->appendChild (new TextNode (m_doc, s));
1656     if (s != old)
1657         stateChanged (ref);
1658 }
1659 
1660 void SMIL::State::newValue (Node *ref, Where where,
1661         const QString &name, const QString &value) {
1662     NodePtr n = new DarkNode (m_doc, name.toUtf8 ());
1663     switch (where) {
1664         case before:
1665             ref->parentNode ()->insertBefore (n, ref);
1666             break;
1667         case after:
1668             ref->parentNode ()->insertBefore (n, ref->nextSibling ());
1669             break;
1670         default:
1671             ref->appendChild (n);
1672     }
1673     if (!value.isEmpty ()) {
1674         const QString s = exprStringValue (this, value);
1675         n->appendChild (new TextNode (m_doc, s));
1676         stateChanged (ref);
1677     }
1678 }
1679 
1680 void SMIL::State::message (MessageType msg, void *content) {
1681     switch (msg) {
1682 
1683     case MsgMediaReady:
1684         if (media_info && media_info->media) {
1685             if (firstChild ())
1686                 removeChild (firstChild ());
1687             QTextStream in (&((TextMedia *)media_info->media)->text);
1688             readXML (this, in, QString ());
1689             if (firstChild ())
1690                 stateChanged (firstChild ());
1691         }
1692         delete media_info;
1693         media_info = NULL;
1694         postpone_lock = NULL;
1695         return;
1696 
1697     default:
1698         break;
1699     }
1700     Element::message (msg, content);
1701 }
1702 
1703 void *SMIL::State::role (RoleType msg, void *content) {
1704     if (MsgStateChanged == (MessageType) (long) content)
1705         return &m_StateChangeListeners;
1706     return Element::role (msg, content);
1707 }
1708 
1709 //-----------------------------------------------------------------------------
1710 
1711 KDE_NO_CDTOR_EXPORT SMIL::Layout::Layout (NodePtr & d)
1712  : Element (d, id_node_layout) {}
1713 
1714 KDE_NO_EXPORT Node *SMIL::Layout::childFromTag (const QString & tag) {
1715     QByteArray ba = tag.toLatin1 ();
1716     const char *ctag = ba.constData ();
1717     if (!strcmp (ctag, "root-layout")) {
1718         Node *e = new SMIL::RootLayout (m_doc);
1719         root_layout = e;
1720         return e;
1721     } else if (!strcmp (ctag, "region"))
1722         return new SMIL::Region (m_doc);
1723     else if (!strcmp (ctag, "regPoint"))
1724         return new SMIL::RegPoint (m_doc);
1725     return NULL;
1726 }
1727 
1728 KDE_NO_EXPORT void SMIL::Layout::closed () {
1729     if (!root_layout) { // just add one if none there
1730         root_layout = new SMIL::RootLayout (m_doc);
1731         root_layout->setAuxiliaryNode (true);
1732         insertBefore (root_layout, firstChild ());
1733         root_layout->closed ();
1734     } else if (root_layout.ptr () != firstChild ()) {
1735         NodePtr rl = root_layout;
1736         removeChild (root_layout);
1737         insertBefore (root_layout, firstChild ());
1738     }
1739     Element::closed ();
1740 }
1741 
1742 KDE_NO_EXPORT void SMIL::Layout::message (MessageType msg, void *content) {
1743     if (MsgChildFinished == msg) {
1744         headChildDone (this, ((Posting *) content)->source.ptr ());
1745         if (state_finished == state && root_layout)
1746             root_layout->message (MsgSurfaceBoundsUpdate, (void *) true);
1747         return;
1748     }
1749     Element::message (msg, content);
1750 }
1751 
1752 //-----------------------------------------------------------------------------
1753 
1754 KDE_NO_CDTOR_EXPORT SMIL::RegionBase::RegionBase (NodePtr & d, short id)
1755  : Element (d, id),
1756    media_info (NULL),
1757    z_order (0)
1758 {}
1759 
1760 KDE_NO_CDTOR_EXPORT SMIL::RegionBase::~RegionBase () {
1761     if (region_surface)
1762         region_surface->remove ();
1763 }
1764 
1765 KDE_NO_EXPORT void SMIL::RegionBase::activate () {
1766     show_background = ShowAlways;
1767     background_color.init ();
1768     media_opacity.init ();
1769     bg_repeat = BgRepeat;
1770     fit = fit_default;
1771     Node *n = parentNode ();
1772     if (n && SMIL::id_node_layout == n->id)
1773         n = n->firstChild ();
1774     state = state_deferred;
1775     role (RoleDisplay);
1776     font_props.init ();
1777     init ();
1778     Element::activate ();
1779 }
1780 
1781 KDE_NO_EXPORT void SMIL::RegionBase::deactivate () {
1782     show_background = ShowAlways;
1783     background_color.init ();
1784     background_image.truncate (0);
1785     if (media_info) {
1786         delete media_info;
1787         media_info = NULL;
1788     }
1789     postpone_lock = NULL;
1790     sizes.resetSizes ();
1791     Element::deactivate ();
1792 }
1793 
1794 KDE_NO_EXPORT void SMIL::RegionBase::dataArrived () {
1795     ImageMedia *im = media_info ? (ImageMedia *)media_info->media : NULL;
1796     if (im && !im->isEmpty () && region_surface) {
1797         region_surface->markDirty ();
1798         region_surface->repaint ();
1799     }
1800     postpone_lock = 0L;
1801 }
1802 
1803 KDE_NO_EXPORT void SMIL::RegionBase::repaint () {
1804     Surface *s = (Surface *) role (RoleDisplay);
1805     if (s)
1806         s->repaint ();
1807 }
1808 
1809 KDE_NO_EXPORT void SMIL::RegionBase::repaint (const SRect & rect) {
1810     Surface *s = (Surface *) role (RoleDisplay);
1811     if (s)
1812         s->repaint (SRect (0, 0, s->bounds.size).intersect (rect));
1813 }
1814 
1815 static void updateSurfaceSort (SMIL::RegionBase *rb) {
1816     Surface *rs = rb->region_surface.ptr ();
1817     Surface *prs = rs->parentNode ();
1818     Surface *next = NULL;
1819     if (!prs)
1820         return;
1821     for (Surface *s = prs->firstChild (); s; s = s->nextSibling ())
1822         if (s != rs && s->node) {
1823             if (SMIL::id_node_region == s->node->id) {
1824                 SMIL::Region *r = static_cast <SMIL::Region *> (s->node.ptr ());
1825                 if (r->z_order > rb->z_order) {
1826                     next = s;
1827                     break;
1828                 } else if (r->z_order == rb->z_order) {
1829                     next = s;
1830                     // now take region order into account
1831                     Node *n = rb->previousSibling();
1832                     for (; n; n = n->previousSibling())
1833                         if (n->id == SMIL::id_node_region) {
1834                             r = static_cast <SMIL::Region *> (n);
1835                             if (r->region_surface && r->z_order == rb->z_order) {
1836                                 next = r->region_surface->nextSibling ();
1837                                 if (rs == next)
1838                                     next = next->nextSibling ();
1839                                 break;
1840                             }
1841                         }
1842                     break;
1843                 }
1844             } else if (SMIL::id_node_root_layout != s->node->id) {
1845                 // break at attached media types
1846                 Surface *m = (Surface *) s->node->role (RoleDisplay);
1847                 if (m) {
1848                     next = m;
1849                     break;
1850                 }
1851             }
1852         }
1853     if (rs->nextSibling () == next) {
1854         return;
1855     }
1856     SurfacePtr protect (rs);
1857     prs->removeChild (rs);
1858     prs->insertBefore (rs, next);
1859 }
1860 
1861 KDE_NO_EXPORT
1862 void SMIL::RegionBase::parseParam (const TrieString & name, const QString & val) {
1863     bool need_repaint = false;
1864     if (name == Ids::attr_fit) {
1865         Fit ft = parseFit (val.toAscii ().constData ());
1866         if (ft != fit) {
1867             fit = ft;
1868             if (region_surface)
1869                 region_surface->scroll = fit_scroll == fit;
1870             need_repaint = true;
1871         }
1872     } else if (parseBackgroundParam (background_color, name, val) ||
1873             parseMediaOpacityParam (media_opacity, name, val)) {
1874     } else if (name == "z-index") {
1875         z_order = val.toInt ();
1876         if (region_surface)
1877             updateSurfaceSort (this);
1878         need_repaint = true;
1879     } else if (sizes.setSizeParam (name, val)) {
1880         if (state_finished == state && region_surface)
1881             message (MsgSurfaceBoundsUpdate);
1882     } else if (name == "showBackground") {
1883         if (val == "whenActive")
1884             show_background = ShowWhenActive;
1885         else
1886             show_background = ShowAlways;
1887         need_repaint = true;
1888     } else if (name == "backgroundRepeat") {
1889         if (val == "noRepeat")
1890             bg_repeat = BgNoRepeat;
1891         else if (val == "repeatX")
1892             bg_repeat = BgRepeatX;
1893         else if (val == "repeatY")
1894             bg_repeat = BgRepeatY;
1895         else if (val == "inherit")
1896             bg_repeat = BgInherit;
1897         else
1898             bg_repeat = BgRepeat;
1899     } else if (name == "backgroundImage") {
1900         if (val.isEmpty () || val == "none" || val == "inherit") {
1901             need_repaint = !background_image.isEmpty () &&
1902                 background_image != val;
1903             background_image = val;
1904             if (media_info) {
1905                 delete media_info;
1906                 media_info = NULL;
1907                 postpone_lock = NULL;
1908             }
1909         } else if (background_image != val) {
1910             background_image = val;
1911             Smil *s = val.isEmpty () ? NULL : SMIL::Smil::findSmilNode (this);
1912             if (s) {
1913                 if (!media_info)
1914                     media_info = new MediaInfo (this, MediaManager::Image);
1915                 Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
1916                 QString url = mrl ? KURL (mrl->absolutePath(), val).url() : val;
1917                 postpone_lock = document ()->postpone ();
1918                 media_info->wget (url);
1919             }
1920         }
1921     } else {
1922         font_props.parseParam (name, val);
1923     }
1924     if (active ()) {
1925         Surface *s = (Surface *) role (RoleDisplay);
1926         if (s && s->background_color != background_color.color){
1927             s->setBackgroundColor (background_color.color);
1928             need_repaint = true;
1929         }
1930         if (need_repaint && s)
1931             s->repaint ();
1932     }
1933     Element::parseParam (name, val);
1934 }
1935 
1936 void SMIL::RegionBase::message (MessageType msg, void *content) {
1937     switch (msg) {
1938 
1939     case MsgMediaReady:
1940         if (media_info)
1941             dataArrived ();
1942         return;
1943 
1944     case MsgChildFinished:
1945         headChildDone (this, ((Posting *) content)->source.ptr ());
1946         return;
1947 
1948     default:
1949         break;
1950     }
1951     Element::message (msg, content);
1952 }
1953 
1954 void *SMIL::RegionBase::role (RoleType msg, void *content) {
1955     switch (msg) {
1956 
1957     case RoleSizer:
1958         return &sizes;
1959 
1960     case RoleReceivers:
1961         if (MsgSurfaceAttach == (MessageType) (long) content)
1962             return &m_AttachedMediaTypes;
1963         // fall through
1964 
1965     default:
1966         break;
1967     }
1968     return Element::role (msg, content);
1969 }
1970 
1971 
1972 //--------------------------%<-------------------------------------------------
1973 
1974 KDE_NO_EXPORT void SMIL::RootLayout::closed () {
1975     QString width = getAttribute (Ids::attr_width);
1976     QString height = getAttribute (Ids::attr_height);
1977     if (!width.isEmpty () && !height.isEmpty ()) {
1978         Smil *s = Smil::findSmilNode (this);
1979         if (s) {
1980             s->size.width = width.toDouble ();
1981             s->size.height = height.toDouble();
1982         }
1983     }
1984     Element::closed ();
1985 }
1986 
1987 KDE_NO_CDTOR_EXPORT SMIL::RootLayout::~RootLayout() {
1988 }
1989 
1990 KDE_NO_EXPORT void SMIL::RootLayout::deactivate () {
1991     SMIL::Smil *s = Smil::findSmilNode (this);
1992     if (s)
1993         s->role (RoleChildDisplay, NULL);
1994     if (region_surface) {
1995         region_surface->remove ();
1996         region_surface = NULL;
1997     }
1998     RegionBase::deactivate ();
1999 }
2000 
2001 void SMIL::RootLayout::message (MessageType msg, void *content) {
2002     switch (msg) {
2003 
2004     case MsgSurfaceBoundsUpdate:
2005         if (region_surface) {
2006             Surface *surface = region_surface.ptr ();
2007             Surface *ps = surface->parentNode ();
2008             Single x, y, w, h, pw, ph;
2009             if (ps && auxiliaryNode ()) {
2010                 w = ps->bounds.width ();
2011                 h = ps->bounds.height ();
2012                 sizes.width = QString::number ((int) w);
2013                 sizes.height = QString::number ((int) h);
2014             } else {
2015                 w = sizes.width.size ();
2016                 h = sizes.height.size ();
2017                 if (ps) {
2018                     pw = ps->bounds.width ();
2019                     ph = ps->bounds.height ();
2020                     double pasp = (double) pw / ph;
2021                     double asp = (double) w / h;
2022                     if (pasp > asp) {
2023                         ps->xscale = ps->yscale = 1.0 * ph / h;
2024                         x += (Single (pw/ps->yscale) -  w) / 2;
2025                     } else {
2026                         ps->xscale = ps->yscale = 1.0 * pw / w;
2027                         y += (Single (ph/ps->xscale) - h) / 2;
2028                     }
2029                 }
2030             }
2031             if (content || surface->bounds.size != SSize (w, h)) {
2032                 surface->bounds = SRect (x, y, w, h);
2033                 if (!auxiliaryNode ()) {
2034                     SMIL::Smil *s = Smil::findSmilNode (this);
2035                     s->size = surface->bounds.size;
2036                 }
2037                 if (content)
2038                     surface->resize (surface->bounds, true);
2039                 else
2040                     surface->updateChildren (!!content);
2041             }
2042         }
2043         return;
2044 
2045     default:
2046         break;
2047     }
2048     RegionBase::message (msg, content);
2049 }
2050 
2051 void *SMIL::RootLayout::role (RoleType msg, void *content) {
2052     switch (msg) {
2053 
2054     case RoleDisplay:
2055         if (!region_surface && active ()) {
2056             SMIL::Smil *s = Smil::findSmilNode (this);
2057             if (s && s->active ()) {
2058                 Surface *surface = (Surface *)s->role (RoleChildDisplay, s);
2059                 if (surface) {
2060                     region_surface = surface->createSurface (this, SRect ());
2061                     // FIXME, silly heuristic to allow transparency in nesting
2062                     if (!background_color.color
2063                             && (!s->parentNode ()
2064                                 || s->parentNode()->id < id_node_smil))
2065                         background_color.color = 0xFFFFFAFA; // snow
2066                 }
2067             }
2068         }
2069         return region_surface.ptr ();
2070 
2071     default:
2072         break;
2073     }
2074     return RegionBase::role (msg, content);
2075 }
2076 
2077 //--------------------------%<-------------------------------------------------
2078 
2079 KDE_NO_CDTOR_EXPORT SMIL::Region::Region (NodePtr & d)
2080  : RegionBase (d, id_node_region) {}
2081 
2082 KDE_NO_CDTOR_EXPORT SMIL::Region::~Region () {
2083 }
2084 
2085 KDE_NO_EXPORT void SMIL::Region::deactivate () {
2086     if (region_surface)
2087         region_surface->remove ();
2088     RegionBase::deactivate ();
2089 }
2090 
2091 KDE_NO_EXPORT Node *SMIL::Region::childFromTag (const QString & tag) {
2092     if (!strcmp (tag.toLatin1 ().constData (), "region"))
2093         return new SMIL::Region (m_doc);
2094     return NULL;
2095 }
2096 
2097 void SMIL::Region::message (MessageType msg, void *content) {
2098     switch (msg) {
2099 
2100     case MsgSurfaceBoundsUpdate:
2101         if (region_surface && state == state_finished) {
2102             Surface *ps = region_surface->parentNode ();
2103             if (ps) {
2104                 SSize dim = ps->bounds.size;
2105                 Single x, y, w, h;
2106                 sizes.calcSizes (this, NULL, dim.width, dim.height, x, y, w, h);
2107                 region_surface->resize (SRect (x, y, w, h), !!content);
2108             }
2109         }
2110         return;
2111 
2112     default:
2113         break;
2114     }
2115     RegionBase::message (msg, content);
2116 }
2117 
2118 void *SMIL::Region::role (RoleType msg, void *content) {
2119     switch (msg) {
2120 
2121     case RoleDisplay:
2122         if (!region_surface && active ()) {
2123             Node *n = parentNode ();
2124             if (n && SMIL::id_node_layout == n->id)
2125                 n = n->firstChild ();
2126             Surface *s = (Surface *) n->role (RoleDisplay);
2127             if (s) {
2128                 region_surface = s->createSurface (this, SRect ());
2129                 region_surface->background_color = background_color.color;
2130                 updateSurfaceSort (this);
2131             }
2132         }
2133         return region_surface.ptr ();
2134 
2135     default: {
2136         ConnectionList *l = mouse_listeners.receivers ((MessageType)(long)content);
2137         if (l)
2138             return l;
2139     }
2140     }
2141     return RegionBase::role (msg, content);
2142 }
2143 
2144 
2145 //-----------------------------------------------------------------------------
2146 
2147 KDE_NO_EXPORT
2148 void SMIL::RegPoint::parseParam (const TrieString & p, const QString & v) {
2149     sizes.setSizeParam (p, v); // TODO: if dynamic, make sure to repaint
2150     Element::parseParam (p, v);
2151 }
2152 
2153 //-----------------------------------------------------------------------------
2154 
2155 static struct TransTypeInfo {
2156     const char *name;
2157     SMIL::Transition::TransType type;
2158     short sub_types;
2159     SMIL::Transition::TransSubType sub_type[8];
2160 } transition_type_info[] = {
2161 #include "transitions.txt"
2162 };
2163 
2164 static struct SubTransTypeInfo {
2165     const char *name;
2166     SMIL::Transition::TransSubType sub_type;
2167 } sub_transition_type_info[] = {
2168 #include "subtrans.txt"
2169 };
2170 
2171 static TransTypeInfo *transInfoFromString (const char *t) {
2172     // TODO binary search
2173     for (int i = 0; transition_type_info[i].name; ++i)
2174         if (!strcmp (t, transition_type_info[i].name))
2175             return transition_type_info + i;
2176     return NULL;
2177 }
2178 
2179 static
2180 SMIL::Transition::TransSubType subTransInfoFromString (const char *s) {
2181     for (int i = 0; sub_transition_type_info[i].name; ++i)
2182         if (!strcmp (s, sub_transition_type_info[i].name))
2183             return sub_transition_type_info[i].sub_type;
2184     return SMIL::Transition::SubTransTypeNone;
2185 }
2186 
2187 KDE_NO_CDTOR_EXPORT SMIL::Transition::Transition (NodePtr & d)
2188  : Element (d, id_node_transition),
2189    type_info (NULL), direction (dir_forward), dur (100), fade_color (0) {}
2190 
2191 KDE_NO_EXPORT void SMIL::Transition::activate () {
2192     type = TransTypeNone;
2193     sub_type = SubTransTypeNone;
2194     start_progress = 0.0;
2195     end_progress = 1.0;
2196     type_info = NULL;
2197     init ();
2198     Element::activate ();
2199 }
2200 
2201 KDE_NO_EXPORT
2202 void SMIL::Transition::parseParam (const TrieString & para, const QString & val) {
2203     if (para == Ids::attr_type) {
2204         type_info = transInfoFromString (val.toAscii ().constData ());
2205         if (type_info) {
2206             type = type_info->type;
2207             if (SubTransTypeNone != sub_type) {
2208                 for (int i = 0; i < type_info->sub_types; ++i)
2209                     if (type_info->sub_type[i] == sub_type)
2210                         return;
2211             }
2212             if (type_info->sub_types > 0)
2213                 sub_type = type_info->sub_type[0];
2214         }
2215     } else if (para == Ids::attr_dur) {
2216         parseTime (val, dur);
2217     } else if (para == "subtype") {
2218         sub_type = subTransInfoFromString (val.toAscii ().constData ());
2219         if (type_info) {
2220             if (SubTransTypeNone != sub_type) {
2221                 for (int i = 0; i < type_info->sub_types; ++i)
2222                     if (type_info->sub_type[i] == sub_type)
2223                         return;
2224             }
2225             if (type_info->sub_types > 0)
2226                 sub_type = type_info->sub_type[0];
2227         }
2228     } else if (para == "fadeColor") {
2229         fade_color = QColor (getAttribute (val)).rgb ();
2230     } else if (para == "direction") {
2231         direction = val == "reverse" ? dir_reverse : dir_forward;
2232     } else if (para == "startProgress") {
2233         start_progress = val.toDouble();
2234         if (start_progress < 0.0)
2235             start_progress = 0.0;
2236         else if (start_progress > 1.0)
2237             start_progress = 1.0;
2238     } else if (para == "endProgress") {
2239         end_progress = val.toDouble();
2240         if (end_progress < start_progress)
2241             end_progress = start_progress;
2242         else if (end_progress > 1.0)
2243             end_progress = 1.0;
2244     } else {
2245         Element::parseParam (para, val);
2246     }
2247 }
2248 
2249 KDE_NO_EXPORT bool SMIL::Transition::supported () {
2250     switch (type) {
2251         case Fade:
2252         case BarWipe:
2253         case BowTieWipe:
2254         case PushWipe:
2255         case IrisWipe:
2256         case ClockWipe:
2257         case EllipseWipe:
2258             return true;
2259         default:
2260             return false;
2261     }
2262 }
2263 
2264 //-----------------------------------------------------------------------------
2265 
2266 KDE_NO_CDTOR_EXPORT SMIL::GroupBase::GroupBase (NodePtr & d, short id)
2267  : Element (d, id),
2268    runtime (new Runtime (this)) {}
2269 
2270 KDE_NO_CDTOR_EXPORT SMIL::GroupBase::~GroupBase () {
2271     delete runtime;
2272 }
2273 
2274 KDE_NO_EXPORT Node *SMIL::GroupBase::childFromTag (const QString & tag) {
2275     Element * elm = fromScheduleGroup (m_doc, tag);
2276     if (!elm) elm = fromMediaContentGroup (m_doc, tag);
2277     if (!elm) elm = fromContentControlGroup (m_doc, tag);
2278     if (!elm) elm = fromAnimateGroup (m_doc, tag);
2279     if (elm)
2280         return elm;
2281     return NULL;
2282 }
2283 
2284 KDE_NO_EXPORT void SMIL::GroupBase::init () {
2285     if (Runtime::TimingsInitialized > runtime->timingstate) {
2286         Element::init ();
2287         runtime->initialize ();
2288     }
2289 }
2290 
2291 KDE_NO_EXPORT void SMIL::GroupBase::finish () {
2292     setState (state_finished); // avoid recurstion through childDone
2293     for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2294         if (e->unfinished ())
2295             e->finish ();
2296     runtime->finish ();
2297 }
2298 
2299 namespace {
2300 
2301 class KMPLAYER_NO_EXPORT GroupBaseInitVisitor : public Visitor {
2302 public:
2303     using Visitor::visit;
2304 
2305     bool ready;
2306 
2307     GroupBaseInitVisitor () : ready (true) {
2308     }
2309 
2310     void visit (Node *node) {
2311         node->message (MsgMediaPrefetch, MsgBool (1));
2312     }
2313     void visit (SMIL::PriorityClass *pc) {
2314         for (NodePtr n = pc->firstChild (); n; n = n->nextSibling ())
2315             n->accept (this);
2316     }
2317     void visit (SMIL::Seq *seq) {
2318         for (Node *n = seq->firstChild (); n; n = n->nextSibling ())
2319             if (n->role (RoleTiming)) {
2320                 seq->firstChild ()->accept (this);
2321                 ready = !!seq->firstChild ()->role (RoleReady);
2322                 break;
2323             }
2324     }
2325     void visit (SMIL::Switch *s) {
2326         Node *n = s->chosenOne ();
2327         if (n)
2328              n->accept (this);
2329     }
2330     void visit (SMIL::Anchor *a) {
2331         if (a->firstChild ())
2332              a->firstChild ()->accept (this);
2333     }
2334     void visit (SMIL::Par *par) {
2335         for (NodePtr n = par->firstChild (); n; n = n->nextSibling ()) {
2336             n->accept (this);
2337             if (ready)
2338                 ready = !!n->role (RoleReady);
2339         }
2340     }
2341 };
2342 
2343 class KMPLAYER_NO_EXPORT FreezeStateUpdater : public Visitor {
2344 
2345     bool initial_node;
2346     bool freeze;
2347 
2348     void setFreezeState (Runtime *rt) {
2349         bool auto_freeze = (Runtime::DurTimer == rt->durTime ().durval &&
2350                     0 == rt->durTime ().offset &&
2351                     Runtime::DurMedia == rt->endTime ().durval) &&
2352             rt->fill_active != Runtime::fill_remove;
2353         bool cfg_freeze = rt->fill_active == Runtime::fill_freeze ||
2354             rt->fill_active == Runtime::fill_hold ||
2355             rt->fill_active == Runtime::fill_transition;
2356 
2357         bool do_freeze = freeze && (auto_freeze || cfg_freeze);
2358         if (do_freeze && rt->timingstate == Runtime::timings_stopped) {
2359             rt->timingstate = Runtime::timings_freezed;
2360             rt->element->message (MsgStateFreeze);
2361         } else if (!do_freeze && rt->timingstate == Runtime::timings_freezed) {
2362             rt->timingstate = Runtime::timings_stopped;
2363             rt->element->message (MsgStateFreeze);
2364         }
2365     }
2366     void updateNode (Node *n) {
2367         if (initial_node) {
2368             initial_node = false;
2369         } else {
2370             Runtime *rt = (Runtime *) n->role (RoleTiming);
2371             if (rt && rt->timingstate >= Runtime::timings_stopped)
2372                 setFreezeState (rt);
2373         }
2374     }
2375 public:
2376     using Visitor::visit;
2377 
2378     FreezeStateUpdater () : initial_node (true), freeze (true) {}
2379 
2380     void visit (Element *elm) {
2381         updateNode (elm);
2382     }
2383     void visit (SMIL::PriorityClass *pc) {
2384         for (NodePtr n = pc->firstChild (); n; n = n->nextSibling ())
2385             n->accept (this);
2386     }
2387     void visit (SMIL::Seq *seq) {
2388         bool old_freeze = freeze;
2389 
2390         updateNode (seq);
2391         freeze = freeze && seq->runtime->active ();
2392 
2393         Runtime *prev = NULL;
2394         for (NodePtr n = seq->firstChild (); n; n = n->nextSibling ()) {
2395             if (n->active ()) {
2396                 Runtime *rt = (Runtime *) n->role (RoleTiming);
2397                 if (rt) {
2398                     bool prev_freeze = prev && freeze &&
2399                         (prev->fill_active == Runtime::fill_hold ||
2400                          (prev->fill_active == Runtime::fill_transition &&
2401                           Runtime::TimingsTransIn == rt->state ()));
2402                     if (rt->timingstate < Runtime::timings_started) {
2403                         break;
2404                     } else if (rt->timingstate < Runtime::timings_stopped) {
2405                         freeze = prev_freeze;
2406                         break;
2407                     }
2408                     if (prev_freeze)
2409                         prev->element->accept (this);
2410                     if (prev &&
2411                             (!prev_freeze ||
2412                              prev->timingstate == Runtime::timings_stopped))
2413                         prev->element->deactivate();
2414                     prev = rt;
2415                 }
2416             }
2417         }
2418         if (prev) {
2419             prev->element->accept (this);
2420             if (prev->timingstate == Runtime::timings_stopped)
2421                 prev->element->deactivate();
2422         }
2423 
2424         freeze = old_freeze;
2425     }
2426     void visit (SMIL::Anchor *a) {
2427         if (a->firstChild ())
2428             a->firstChild ()->accept (this);
2429     }
2430     void visit (SMIL::Par *par) {
2431         bool old_freeze = freeze;
2432 
2433         updateNode (par);
2434         freeze = freeze && par->runtime->active ();
2435 
2436         for (NodePtr n = par->firstChild (); n; n = n->nextSibling ())
2437             n->accept (this);
2438 
2439         freeze = old_freeze;
2440     }
2441     void visit (SMIL::Excl *excl) {
2442         bool old_freeze = freeze;
2443 
2444         updateNode (excl);
2445         bool new_freeze = freeze && excl->runtime->active ();
2446 
2447         Node *cur = excl->cur_node.ptr ();
2448         for (NodePtr n = excl->firstChild (); n; n = n->nextSibling ()) {
2449             freeze = new_freeze && n.ptr () == cur;
2450             n->accept (this);
2451         }
2452 
2453         freeze = old_freeze;
2454     }
2455     void visit (SMIL::Switch *s) {
2456         bool old_freeze = freeze;
2457 
2458         updateNode (s);
2459         freeze &= s->runtime->active ();
2460 
2461         Node *cur = s->chosenOne ();
2462         if (cur)
2463             cur->accept (this);
2464 
2465         freeze = old_freeze;
2466     }
2467 };
2468 
2469 }
2470 
2471 KDE_NO_EXPORT void SMIL::GroupBase::activate () {
2472     init ();
2473     GroupBaseInitVisitor visitor;
2474     accept (&visitor);
2475     setState (state_activated);
2476     if (visitor.ready)
2477         runtime->start ();
2478     else
2479         state = state_deferred;
2480 }
2481 
2482 KDE_NO_EXPORT
2483 void SMIL::GroupBase::parseParam (const TrieString &para, const QString &val) {
2484     if (!runtime->parseParam (para, val))
2485         Element::parseParam (para, val);
2486 }
2487 
2488 KDE_NO_EXPORT void SMIL::GroupBase::message (MessageType msg, void *content) {
2489     switch (msg) {
2490 
2491     case MsgStateRewind:
2492         if (active ()) {
2493             State old = state;
2494             state = state_deactivated;
2495             for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2496                 e->reset ();
2497             state = old;
2498             GroupBaseInitVisitor visitor;
2499             accept (&visitor);
2500         }
2501         return;
2502 
2503     default:
2504         break;
2505     }
2506     if ((int) msg >= (int) Runtime::DurLastDuration)
2507         Element::message (msg, content);
2508     else
2509         runtime->message (msg, content);
2510 }
2511 
2512 KDE_NO_EXPORT void *SMIL::GroupBase::role (RoleType msg, void *content) {
2513     switch (msg) {
2514 
2515     case RoleTiming:
2516         if (Runtime::TimingsInitialized > runtime->timingstate)
2517             init ();
2518         return runtime;
2519 
2520     default:
2521         break;
2522     }
2523     void *response = runtime->role (msg, content);
2524     if (response == MsgUnhandled)
2525         return Element::role (msg, content);
2526     return response;
2527 }
2528 
2529 
2530 KDE_NO_EXPORT void SMIL::GroupBase::deactivate () {
2531     bool need_finish (unfinished ());
2532     setState (state_deactivated); // avoid recurstion through childDone
2533     for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2534         if (e->active ())
2535             e->deactivate ();
2536         else
2537             e->message (MsgMediaPrefetch, MsgBool (0));
2538     if (need_finish)
2539         finish ();
2540     runtime->init ();
2541     Element::deactivate ();
2542 }
2543 
2544 KDE_NO_EXPORT void SMIL::GroupBase::reset () {
2545     Element::reset ();
2546     runtime->init ();
2547 }
2548 
2549 KDE_NO_EXPORT void SMIL::GroupBase::setJumpNode (NodePtr n) {
2550     NodePtr child = n;
2551     if (state > state_init) {
2552         state = state_deferred;
2553         for (NodePtr c = firstChild (); c; c = c->nextSibling ())
2554             if (c->active ())
2555                 c->reset ();
2556         for (Node *c = n->parentNode (); c; c = c->parentNode ()) {
2557             if (c == this || c->id == id_node_body)
2558                 break;
2559             if (c->id >= id_node_first_group && c->id <= id_node_last_group)
2560                 static_cast <SMIL::GroupBase *> (c)->jump_node = child;
2561             child = c;
2562         }
2563     }
2564     jump_node = child;
2565     state = state_activated;
2566     init ();
2567     for (NodePtr n = firstChild (); n; n = n->nextSibling ())
2568         if (n->role (RoleTiming))
2569             convertNode <Element> (n)->init ();
2570     runtime->startAndBeginNode (); // undefer through begin()
2571 }
2572 
2573 //-----------------------------------------------------------------------------
2574 
2575 // SMIL::Body was here
2576 
2577 //-----------------------------------------------------------------------------
2578 
2579 KDE_NO_EXPORT void SMIL::Par::begin () {
2580     jump_node = 0L; // TODO: adjust timings
2581     setState (state_began);
2582     for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2583         e->activate ();
2584 }
2585 
2586 KDE_NO_EXPORT void SMIL::Par::reset () {
2587     GroupBase::reset ();
2588     for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2589         e->reset ();
2590 }
2591 
2592 static bool childrenReady (Node *node) {
2593     for (Node *n = node->firstChild (); n; n = n->nextSibling ())
2594         if (!n->role (RoleReady))
2595             return false;
2596     return true;
2597 }
2598 
2599 KDE_NO_EXPORT void SMIL::Par::message (MessageType msg, void *content) {
2600     switch (msg) {
2601 
2602     case MsgChildReady:
2603         if (childrenReady (this)) {
2604             const int cur_state = state;
2605             if (state == state_deferred) {
2606                 state = state_activated;
2607                 runtime->start ();
2608             }
2609             if (cur_state == state_init && parentNode ())
2610                 parentNode ()->message (MsgChildReady, this);
2611         }
2612         return;
2613 
2614     case MsgChildFinished: {
2615         if (unfinished ()) {
2616             FreezeStateUpdater visitor;
2617             accept (&visitor);
2618             runtime->tryFinish ();
2619         }
2620         return;
2621     }
2622     default:
2623         break;
2624     }
2625     GroupBase::message (msg, content);
2626 }
2627 
2628 KDE_NO_EXPORT void *SMIL::Par::role (RoleType msg, void *content) {
2629     switch (msg) {
2630     case RoleReady:
2631         return MsgBool (childrenReady (this));
2632     default:
2633         break;
2634     }
2635     return GroupBase::role (msg, content);
2636 }
2637 
2638 
2639 //-----------------------------------------------------------------------------
2640 
2641 KDE_NO_EXPORT void SMIL::Seq::begin () {
2642     setState (state_began);
2643     if (jump_node) {
2644         starting_connection.disconnect ();
2645         trans_connection.disconnect ();
2646         for (NodePtr c = firstChild (); c; c = c->nextSibling ())
2647             if (c == jump_node) {
2648                 jump_node = 0L;
2649                 c->activate ();
2650                 break;
2651             } else {
2652                 c->state = state_activated; // TODO: ..
2653                 if (c->isElementNode ())
2654                     convertNode <Element> (c)->init ();
2655                 c->state = state_finished; // TODO: ..
2656                 Runtime *rt = (Runtime *) c->role (RoleTiming);
2657                 if (rt)
2658                     rt->timingstate = Runtime::timings_stopped; //TODO fill_hold
2659             }
2660     } else if (firstChild ()) {
2661         if (firstChild ()->nextSibling()) {
2662             GroupBaseInitVisitor visitor;
2663             firstChild ()->nextSibling ()->accept (&visitor);
2664         }
2665         starting_connection.connect (firstChild (), MsgEventStarted, this);
2666         firstChild ()->activate ();
2667     }
2668 }
2669 
2670 KDE_NO_EXPORT void SMIL::Seq::message (MessageType msg, void *content) {
2671     switch (msg) {
2672 
2673         case MsgChildReady:
2674             if (firstChild () == (Node *) content) {
2675                 if (state == state_deferred) {
2676                     state = state_activated;
2677                     runtime->start ();
2678                 }
2679                 if (state == state_init && parentNode ())
2680                     parentNode ()->message (MsgChildReady, this);
2681             } else if (unfinished ()) {
2682                 FreezeStateUpdater visitor;
2683                 accept (&visitor);
2684             }
2685             return;
2686 
2687         case MsgChildFinished: {
2688             if (unfinished ()) {
2689                 Posting *post = (Posting *) content;
2690                 if (state != state_deferred) {
2691                     Node *next = post->source
2692                         ? post->source->nextSibling ()
2693                         : NULL;
2694                     if (next) {
2695                         if (next->nextSibling()) {
2696                             GroupBaseInitVisitor visitor;
2697                             next->nextSibling ()->accept (&visitor);
2698                         }
2699                         starting_connection.connect(next, MsgEventStarted,this);
2700                         trans_connection.connect (
2701                                 next, MsgChildTransformedIn, this);
2702                         next->activate ();
2703                     } else {
2704                         starting_connection.disconnect ();
2705                         trans_connection.disconnect ();
2706                         runtime->tryFinish ();
2707                     }
2708                     FreezeStateUpdater visitor;
2709                     accept (&visitor);
2710                 } else if (jump_node) {
2711                     finish ();
2712                 }
2713             }
2714             return;
2715         }
2716 
2717         case MsgEventStarted: {
2718             Posting *event = static_cast <Posting *> (content);
2719             Node *source = event->source;
2720             if (source != this && source->previousSibling ()) {
2721                 FreezeStateUpdater visitor;
2722                 starting_connection.disconnect ();
2723                 accept (&visitor);
2724             }
2725             break;
2726         }
2727 
2728         case MsgChildTransformedIn: {
2729             Node *source = (Node *) content;
2730             if (source != this && source->previousSibling ()) {
2731                 FreezeStateUpdater visitor;
2732                 starting_connection.disconnect ();
2733                 accept (&visitor);
2734             }
2735             break;
2736         }
2737 
2738         default:
2739             break;
2740     }
2741     GroupBase::message (msg, content);
2742 }
2743 
2744 KDE_NO_EXPORT void *SMIL::Seq::role (RoleType msg, void *content) {
2745     switch (msg) {
2746     case RoleReady:
2747         return MsgBool (!firstChild () || firstChild ()->role (RoleReady));
2748     default:
2749         break;
2750     }
2751     return GroupBase::role (msg, content);
2752 }
2753 
2754 
2755 //-----------------------------------------------------------------------------
2756 
2757 KDE_NO_EXPORT Node *SMIL::Excl::childFromTag (const QString &tag) {
2758     if (tag == "priorityClass")
2759         return new PriorityClass (m_doc);
2760     return GroupBase::childFromTag (tag);
2761 }
2762 
2763 namespace {
2764 
2765 class KMPLAYER_NO_EXPORT ExclActivateVisitor : public Visitor {
2766     SMIL::Excl *excl;
2767 public:
2768     ExclActivateVisitor (SMIL::Excl *ex) : excl (ex) {}
2769 
2770     using Visitor::visit;
2771 
2772     void visit (Node *n) {
2773         Node *s = n->nextSibling ();
2774         if (s)
2775             s->accept (this);
2776     }
2777     void visit (Element *elm) {
2778         if (elm->role (RoleTiming)) {
2779             // make aboutToStart connection with Timing
2780             excl->started_event_list =
2781                 new SMIL::Excl::ConnectionItem (excl->started_event_list);
2782             excl->started_event_list->link.connect (elm, MsgEventStarting, excl);
2783             elm->activate ();
2784         }
2785         visit (static_cast <Node *> (elm));
2786     }
2787     void visit (SMIL::PriorityClass *pc) {
2788         pc->init ();
2789         pc->state = Node::state_activated;
2790         Node *n = pc->firstChild ();
2791         if (n)
2792             n->accept (this);
2793         visit (static_cast <Node *> (pc));
2794     }
2795 };
2796 
2797 class KMPLAYER_NO_EXPORT ExclPauseVisitor : public Visitor {
2798     bool pause;
2799     Node *paused_by;
2800     unsigned int cur_time;
2801 
2802     void updatePauseStateEvent (Posting *event, int pause_time) {
2803         if (event) {
2804             if (pause)
2805                 paused_by->document ()->pausePosting (event);
2806             else
2807                 paused_by->document ()->unpausePosting (event, (cur_time-pause_time)*10);
2808         }
2809     }
2810     static Posting *activeEvent (Runtime *r) {
2811         Posting *event = NULL;
2812         if (r->begin_timer)
2813             event = r->begin_timer;
2814         else if (r->started_timer)
2815             event = r->started_timer;
2816         else if (r->duration_timer)
2817             event = r->duration_timer;
2818         else if (r->stopped_timer)
2819             event = r->stopped_timer;
2820         return event;
2821     }
2822 
2823 public:
2824     ExclPauseVisitor (bool p, Node *pb, unsigned int pt)
2825         : pause(p), paused_by (pb), cur_time (pt) {}
2826     ~ExclPauseVisitor () {
2827         paused_by->document ()->updateTimeout ();
2828     }
2829 
2830     using Visitor::visit;
2831 
2832     void visit (Node *node) {
2833         for (Node *c = node->firstChild (); c; c = c->nextSibling ())
2834             c->accept (this);
2835     }
2836     void visit (Element *elm) {
2837         if (!elm->active ())
2838             return; // nothing to do
2839         Runtime *rt = (Runtime *) elm->role (RoleTiming);
2840         if (rt) {
2841             if (pause) {
2842                 rt->paused_time = cur_time;
2843                 rt->paused_by = paused_by;
2844                 rt->unpaused_state = rt->timingstate;
2845                 rt->timingstate = Runtime::timings_paused;
2846             } else {
2847                 rt->paused_by = NULL;
2848                 rt->timingstate = rt->unpaused_state;
2849                 rt->start_time += cur_time;
2850             }
2851             updatePauseStateEvent (activeEvent (rt), rt->paused_time);
2852         }
2853         visit (static_cast <Node *> (elm));
2854     }
2855     void visit (SMIL::MediaType *mt) {
2856         if (mt->media_info && mt->media_info->media) {
2857             if (pause)
2858                 mt->media_info->media->pause ();
2859             else
2860                 mt->media_info->media->unpause ();
2861             Surface *s = mt->surface ();
2862             if (s)
2863                 s->repaint ();
2864         }
2865 
2866         Posting *event = NULL;
2867         if (mt->transition.trans_out_timer)
2868             event = mt->transition.trans_out_timer;
2869         updatePauseStateEvent (event, mt->runtime->paused_time);
2870 
2871         visit (static_cast <Element *> (mt));
2872     }
2873     void visit (SMIL::AnimateBase *an) {
2874         updatePauseStateEvent(an->anim_timer, an->runtime->paused_time);
2875         visit (static_cast <Element *> (an));
2876     }
2877     void visit (SMIL::Smil *s) {
2878         for (Node *c = s->firstChild (); c; c = c->nextSibling ())
2879             if (SMIL::id_node_body == c->id)
2880                 c->accept (this);
2881     }
2882 };
2883 
2884 }
2885 
2886 static void clearList (SMIL::Excl::ConnectionItem **pitem) {
2887     SMIL::Excl::ConnectionItem *item = *pitem;
2888     while (item) {
2889         SMIL::Excl::ConnectionItem *tmp = item;
2890         item = item->next;
2891         delete tmp;
2892     }
2893     *pitem = NULL;
2894 }
2895 
2896 KDE_NO_CDTOR_EXPORT SMIL::Excl::Excl (NodePtr & d)
2897     : GroupBase (d, id_node_excl), started_event_list (NULL) {}
2898 
2899 KDE_NO_CDTOR_EXPORT SMIL::Excl::~Excl () {
2900     clearList (&started_event_list);
2901 }
2902 
2903 KDE_NO_EXPORT void SMIL::Excl::begin () {
2904     Node *n = firstChild ();
2905     if (n) {
2906         ExclActivateVisitor visitor (this);
2907         n->accept (&visitor);
2908     }
2909 }
2910 
2911 KDE_NO_EXPORT void SMIL::Excl::deactivate () {
2912     clearList (&started_event_list);
2913     priority_queue.clear ();
2914     stopped_connection.disconnect ();
2915     GroupBase::deactivate ();
2916 }
2917 
2918 KDE_NO_EXPORT void SMIL::Excl::message (MessageType msg, void *content) {
2919     switch (msg) {
2920         case MsgEventStarting: {
2921             Node *source = (Node *) content;
2922             NodePtr n = cur_node;
2923             if (source == n.ptr ())
2924                 return; // eg. repeating
2925             cur_node = source;
2926             stopped_connection.connect (cur_node, MsgEventStopped, this);
2927             if (n) {
2928                 if (SMIL::id_node_priorityclass == cur_node->parentNode ()->id) {
2929                     switch (static_cast <SMIL::PriorityClass *>
2930                             (cur_node->parentNode ())->peers) {
2931                         case PriorityClass::PeersPause: {
2932                             ExclPauseVisitor visitor (
2933                                   true, this, document ()->last_event_time/10);
2934                             n->accept (&visitor);
2935                             priority_queue.insertBefore (
2936                                   new NodeRefItem (n), priority_queue.first ());
2937                             return;
2938                         }
2939                         default:
2940                             break; //TODO
2941                     }
2942                 }
2943                 ((Runtime*)n->role (RoleTiming))->doFinish ();
2944             }
2945             return;
2946         }
2947         case MsgChildFinished: {
2948             Posting *event = static_cast <Posting *> (content);
2949             FreezeStateUpdater visitor;
2950             accept (&visitor);
2951             if (event->source == cur_node) {
2952                 Runtime* rt = (Runtime*)cur_node->role (RoleTiming);
2953                 if (rt && rt->timingstate == Runtime::timings_stopped) {
2954                     cur_node = NULL;
2955                     stopped_connection.disconnect ();
2956                 }
2957                 runtime->tryFinish ();
2958             }
2959             return;
2960         }
2961         case MsgEventStopped: {
2962             Posting *event = static_cast <Posting *> (content);
2963             if (event->source == cur_node) {
2964 
2965                 NodeRefItemPtr ref = priority_queue.first ();
2966                 while (ref && (!ref->data || !ref->data->active ())) {
2967                     // should not happen, but consider a backend crash or so
2968                     priority_queue.remove (ref);
2969                     ref = priority_queue.first ();
2970                 }
2971                 if (ref) {
2972                     cur_node = ref->data;
2973                     priority_queue.remove (ref);
2974                     stopped_connection.connect (cur_node, MsgEventStopped, this);
2975                     ExclPauseVisitor visitor (false, this, document()->last_event_time/10);
2976                     cur_node->accept (&visitor);
2977                     // else TODO
2978                 }
2979             }
2980             break;
2981         }
2982         default:
2983             break;
2984     }
2985     GroupBase::message (msg, content);
2986 }
2987 
2988 //-----------------------------------------------------------------------------
2989 
2990 KDE_NO_EXPORT Node *SMIL::PriorityClass::childFromTag (const QString &tag) {
2991     Element * elm = fromScheduleGroup (m_doc, tag);
2992     if (!elm) elm = fromMediaContentGroup (m_doc, tag);
2993     if (!elm) elm = fromContentControlGroup (m_doc, tag);
2994     if (!elm) elm = fromAnimateGroup (m_doc, tag);
2995     if (elm)
2996         return elm;
2997     return NULL;
2998 }
2999 
3000 KDE_NO_EXPORT void
3001 SMIL::PriorityClass::parseParam (const TrieString &name, const QString &val) {
3002     if (name == "peers") {
3003         if (val == "pause")
3004             peers = PeersPause;
3005         else if (val == "defer")
3006             peers = PeersDefer;
3007         else if (val == "never")
3008             peers = PeersNever;
3009         else
3010             peers = PeersStop;
3011     } else if (name == "higher") {
3012         if (val == "stop")
3013             higher = HigherStop;
3014         else
3015             higher = HigherPause;
3016     } else if (name == "lower") {
3017         if (val == "never")
3018             lower = LowerNever;
3019         else
3020             lower = LowerDefer;
3021     } else if (name == "pauseDisplay") {
3022         if (val == "disable")
3023             pause_display = PauseDisplayDisable;
3024         else if (val == "hide")
3025             pause_display = PauseDisplayHide;
3026         else
3027             pause_display = PauseDisplayShow;
3028     }
3029 }
3030 
3031 KDE_NO_EXPORT void SMIL::PriorityClass::init () {
3032     peers = PeersStop;
3033     higher = HigherPause;
3034     lower = LowerDefer;
3035     pause_display = PauseDisplayShow;
3036     Element::init ();
3037 }
3038 
3039 KDE_NO_EXPORT void SMIL::PriorityClass::message (MessageType msg, void *data) {
3040     if (MsgChildFinished == msg)
3041         // do nothing
3042         return;
3043     Element::message (msg, data);
3044 }
3045 
3046 //-----------------------------------------------------------------------------
3047 
3048 KDE_NO_EXPORT void SMIL::Switch::init () {
3049     Node *n = chosen_one.ptr ();
3050     chosen_one = NULL;
3051     if (n && n->active ())
3052         n->deactivate ();
3053     GroupBase::init ();
3054 }
3055 
3056 KDE_NO_EXPORT Node *SMIL::Switch::chosenOne () {
3057     if (!chosen_one && firstChild ()) {
3058         PlayListNotify * n = document()->notify_listener;
3059         int pref = 0, max = 0x7fffffff, currate = 0;
3060         if (n)
3061             n->bitRates (pref, max);
3062         if (firstChild ()) {
3063             Node *fallback = NULL;
3064             for (Node *e = firstChild (); e; e = e->nextSibling ())
3065                 if (e->isElementNode ()) {
3066                     Element *elm = static_cast <Element *> (e);
3067                     Runtime *rt = (Runtime *) e->role (RoleTiming);
3068                     if (rt) {
3069                         if (rt->state () < Runtime::TimingsInitialized)
3070                             elm->init ();
3071                         if (!disabledByExpr (rt)) {
3072                             QString lang = elm->getAttribute ("systemLanguage");
3073                             if (!lang.isEmpty ()) {
3074                                 lang = lang.replace (QChar ('-'), QChar ('_'));
3075                                 char *clang = getenv ("LANG");
3076                                 if (!clang) {
3077                                     if (!fallback)
3078                                         fallback = e;
3079                                 } else if (QString (clang).toLower ().startsWith (lang)) {
3080                                     chosen_one = e;
3081                                 } else if (!fallback) {
3082                                     fallback = e->nextSibling ();
3083                                 }
3084                             }
3085                             if (e->id == id_node_ref) {
3086                                 SMIL::MediaType * mt = static_cast<SMIL::MediaType*>(e);
3087                                 if (!chosen_one) {
3088                                     chosen_one = e;
3089                                     currate = mt->bitrate;
3090                                 } else if (int (mt->bitrate) <= max) {
3091                                     int delta1 = pref > currate ? pref-currate : currate-pref;
3092                                     int delta2 = pref > int (mt->bitrate) ? pref-mt->bitrate : mt->bitrate-pref;
3093                                     if (delta2 < delta1) {
3094                                         chosen_one = e;
3095                                         currate = mt->bitrate;
3096                                     }
3097                                 }
3098                             } else if (!fallback)
3099                                 fallback = e;
3100                         }
3101                     }
3102                 }
3103             if (!chosen_one)
3104                 chosen_one = (fallback ? fallback : firstChild ());
3105         }
3106     }
3107     return chosen_one.ptr ();
3108 }
3109 
3110 KDE_NO_EXPORT void SMIL::Switch::begin () {
3111     Node *n = chosenOne ();
3112     if (n)
3113         n->activate ();
3114     else
3115         runtime->tryFinish ();
3116 }
3117 
3118 KDE_NO_EXPORT void SMIL::Switch::deactivate () {
3119     chosen_one = NULL;
3120     GroupBase::deactivate ();
3121 }
3122 
3123 KDE_NO_EXPORT void SMIL::Switch::reset () {
3124     GroupBase::reset ();
3125     for (NodePtr e = firstChild (); e; e = e->nextSibling ()) {
3126         if (e->state != state_init)
3127             e->reset ();
3128     }
3129 }
3130 
3131 KDE_NO_EXPORT void SMIL::Switch::message (MessageType msg, void *content) {
3132     switch (msg) {
3133     case MsgChildFinished: {
3134         Posting *post = (Posting *) content;
3135         if (unfinished () && post->source == chosen_one) {
3136             runtime->tryFinish ();
3137             FreezeStateUpdater visitor;
3138             accept (&visitor);
3139         }
3140         return;
3141     }
3142     case MsgStateRewind:
3143         chosen_one = NULL;
3144         break;
3145     default:
3146         break;
3147     }
3148     GroupBase::message (msg, content);
3149 }
3150 
3151 //-----------------------------------------------------------------------------
3152 
3153 KDE_NO_CDTOR_EXPORT SMIL::LinkingBase::LinkingBase (NodePtr & d, short id)
3154  : Element(d, id), show (show_replace) {}
3155 
3156 KDE_NO_EXPORT void SMIL::LinkingBase::deactivate () {
3157     mediatype_attach.disconnect ();
3158     Element::deactivate ();
3159 }
3160 
3161 KDE_NO_EXPORT
3162 void SMIL::LinkingBase::parseParam(const TrieString &para, const QString &val) {
3163     if (para == Ids::attr_href) {
3164         href = val;
3165     } else if (para == Ids::attr_target) {
3166         target = val;
3167     }
3168 }
3169 
3170 //-----------------------------------------------------------------------------
3171 
3172 KDE_NO_CDTOR_EXPORT SMIL::Anchor::Anchor (NodePtr & d)
3173  : LinkingBase (d, id_node_anchor) {}
3174 
3175 KDE_NO_EXPORT void SMIL::Anchor::activate () {
3176     init ();
3177     for (Node *c = firstChild(); c; c = c->nextSibling ())
3178         if (nodeMessageReceivers (c, MsgEventClicked)) {
3179             mediatype_attach.connect (c, MsgSurfaceAttach, this);
3180             break;
3181         }
3182     Element::activate ();
3183 }
3184 
3185 KDE_NO_EXPORT void SMIL::Anchor::message (MessageType msg, void *content) {
3186     switch (msg) {
3187 
3188         case MsgChildReady:
3189             if (parentNode ())
3190                 parentNode ()->message (MsgChildReady, this);
3191             return;
3192 
3193         case MsgChildFinished: {
3194             Posting *post = (Posting *) content;
3195             if (unfinished ()) {
3196                 if (post->source->nextSibling ())
3197                     post->source->nextSibling ()->activate ();
3198                 else
3199                     finish ();
3200             }
3201             return;
3202         }
3203 
3204         default:
3205             break;
3206     }
3207     LinkingBase::message (msg, content);
3208 }
3209 
3210 Node *SMIL::Anchor::childFromTag (const QString & tag) {
3211     return fromMediaContentGroup (m_doc, tag);
3212 }
3213 
3214 KDE_NO_EXPORT void *SMIL::Anchor::role (RoleType msg, void *content) {
3215     switch (msg) {
3216     case RoleReady:
3217         return MsgBool (childrenReady (this));
3218     default:
3219         break;
3220     }
3221     return LinkingBase::role (msg, content);
3222 }
3223 
3224 
3225 //-----------------------------------------------------------------------------
3226 
3227 KDE_NO_CDTOR_EXPORT SMIL::Area::Area (NodePtr & d, const QString & t)
3228  : LinkingBase (d, id_node_area), coords (0L), nr_coords (0), tag (t.toUtf8()) {}
3229 
3230 KDE_NO_CDTOR_EXPORT SMIL::Area::~Area () {
3231     delete [] coords;
3232 }
3233 
3234 KDE_NO_EXPORT void SMIL::Area::activate () {
3235     init ();
3236     if (parentNode () &&
3237             parentNode ()->id >= id_node_first_mediatype &&
3238             parentNode ()->id <= id_node_last_mediatype) {
3239         mediatype_attach.connect (parentNode (), MsgSurfaceAttach, this);
3240     }
3241     Element::activate ();
3242 }
3243 
3244 KDE_NO_EXPORT
3245 void SMIL::Area::parseParam (const TrieString & para, const QString & val) {
3246     if (para == "coords") {
3247         delete [] coords;
3248         QStringList clist = val.split (QChar (','));
3249         nr_coords = clist.count ();
3250         coords = new SizeType [nr_coords];
3251         for (int i = 0; i < nr_coords; ++i)
3252             coords[i] = clist[i];
3253     } else
3254         LinkingBase::parseParam (para, val);
3255 }
3256 
3257 KDE_NO_EXPORT void *SMIL::Area::role (RoleType msg, void *content) {
3258     ConnectionList *l = mouse_listeners.receivers ((MessageType) (long) content);
3259     if (l)
3260         return l;
3261     return Element::role (msg, content);
3262 }
3263 
3264 //-----------------------------------------------------------------------------
3265 
3266 KDE_NO_CDTOR_EXPORT SMIL::MediaType::MediaType (NodePtr &d, const QByteArray &t, short id)
3267  : Mrl (d, id),
3268    runtime (new Runtime (this)),
3269    m_type (t),
3270    pan_zoom (NULL),
3271    bitrate (0),
3272    sensitivity (sens_opaque) {
3273     view_mode = Mrl::WindowMode;
3274 }
3275 
3276 KDE_NO_CDTOR_EXPORT SMIL::MediaType::~MediaType () {
3277     delete runtime;
3278     delete pan_zoom;
3279 }
3280 
3281 KDE_NO_EXPORT Node *SMIL::MediaType::childFromTag (const QString & tag) {
3282     Element * elm = fromContentControlGroup (m_doc, tag);
3283     if (!elm) elm = fromParamGroup (m_doc, tag);
3284     if (!elm) elm = fromAnimateGroup (m_doc, tag);
3285     if (elm)
3286         return elm;
3287     return NULL;
3288 }
3289 
3290 static NodePtr findExternalTree (Mrl *mrl) {
3291     for (Node *c = mrl->firstChild (); c; c = c->nextSibling ()) {
3292         Mrl * m = c->mrl ();
3293         if (m && (m->opener.ptr () == mrl ||
3294                     m->id == SMIL::id_node_smil ||
3295                     m->id == RP::id_node_imfl))
3296             return c;
3297     }
3298     return 0L;
3299 }
3300 
3301 KDE_NO_EXPORT void SMIL::MediaType::closed () {
3302     external_tree = findExternalTree (this);
3303     Mrl *mrl = external_tree ? external_tree->mrl () : NULL;
3304     if (mrl)
3305         size = mrl->size;
3306     title = getAttribute (Ids::attr_title);
3307     Mrl::closed ();
3308 }
3309 
3310 KDE_NO_EXPORT void SMIL::MediaType::prefetch () {
3311 }
3312 
3313 KDE_NO_EXPORT
3314 void SMIL::MediaType::parseParam (const TrieString &para, const QString & val) {
3315     if (para == Ids::attr_src) {
3316         if (src != val) {
3317             src = val;
3318             if (external_tree)
3319                 removeChild (external_tree);
3320             delete media_info;
3321             media_info = NULL;
3322             if (!val.isEmpty () && runtimeBegan (runtime))
3323                 prefetch ();
3324             if (state == state_began && resolved)
3325                 clipStart ();
3326         }
3327     } else if (para == Ids::attr_fit) {
3328         fit = parseFit (val.toAscii ().constData ());
3329         if (fit != effective_fit)
3330             message (MsgSurfaceBoundsUpdate);
3331     } else if (para == Ids::attr_type) {
3332         mimetype = val;
3333     } else if (para == "panZoom") {
3334         QStringList coords = val.split (QChar (','));
3335         if (coords.size () < 4) {
3336             kWarning () << "panZoom less then four nubmers";
3337             return;
3338         }
3339         if (!pan_zoom)
3340             pan_zoom = new CalculatedSizer;
3341         pan_zoom->left = coords[0];
3342         pan_zoom->top = coords[1];
3343         pan_zoom->width = coords[2];
3344         pan_zoom->height = coords[3];
3345     } else if (parseBackgroundParam (background_color, para, val) ||
3346             parseMediaOpacityParam (media_opacity, para, val)) {
3347     } else if (para == "system-bitrate") {
3348         bitrate = val.toInt ();
3349     } else if (parseTransitionParam (this, transition, runtime, para, val)) {
3350     } else if (para == "sensitivity") {
3351         if (val == "transparent")
3352             sensitivity = sens_transparent;
3353         //else if (val == "percentage") // TODO
3354         //    sensitivity = sens_percentage;
3355         else
3356             sensitivity = sens_opaque;
3357     } else if (sizes.setSizeParam (para, val)) {
3358         message (MsgSurfaceBoundsUpdate);
3359     } else if (!runtime->parseParam (para, val)) {
3360         Mrl::parseParam (para, val);
3361     }
3362     if (sub_surface) {
3363         sub_surface->markDirty ();
3364         sub_surface->setBackgroundColor (background_color.color);
3365         sub_surface->repaint ();
3366     }
3367 }
3368 
3369 KDE_NO_EXPORT void SMIL::MediaType::init () {
3370     if (Runtime::TimingsInitialized > runtime->timingstate) {
3371         fit = fit_default;
3372         effective_fit = fit_default;
3373         background_color.init ();
3374         media_opacity.init ();
3375         transition.init ();
3376         QString pg = getAttribute ("paramGroup");
3377         if (!pg.isEmpty ()) {
3378             Node *head = findHeadNode (SMIL::Smil::findSmilNode(this));
3379             if (head) {
3380                 Expression *expr = evaluateExpr(QString("/paramGroup[@id='" + pg + "']/param").toUtf8());
3381                 if (expr) {
3382                     expr->setRoot (head);
3383                     Expression::iterator it, e = expr->end();
3384                     for (it = expr->begin(); it != e; ++it) {
3385                         if (it->node->isElementNode()) {
3386                             Element *e = static_cast <Element*>(it->node);
3387                             QString n = e->getAttribute (Ids::attr_name);
3388                             if (!n.isEmpty ())
3389                                 parseParam (n, e->getAttribute (Ids::attr_value));
3390                         }
3391                     }
3392                     delete expr;
3393                 }
3394             }
3395         }
3396         Mrl::init (); // sets all attributes
3397         for (NodePtr c = firstChild (); c; c = c->nextSibling ())
3398             if (SMIL::id_node_param == c->id)
3399                 c->activate (); // activate param children
3400         runtime->initialize ();
3401     }
3402 }
3403 
3404 KDE_NO_EXPORT void SMIL::MediaType::activate () {
3405     init (); // sets all attributes
3406     setState (state_activated);
3407     for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
3408         QString v = a->value ();
3409         int p = v.indexOf ('{');
3410         if (p > -1) {
3411             int q = v.indexOf ('}', p + 1);
3412             if (q > -1)
3413                 parseParam (a->name (), applySubstitution (this, v, p, q));
3414         }
3415     }
3416     if (!runtime->started ())
3417         runtime->start ();
3418 }
3419 
3420 KDE_NO_EXPORT void SMIL::MediaType::deactivate () {
3421     region_attach.disconnect ();
3422     if (region_node)
3423         convertNode <SMIL::RegionBase> (region_node)->repaint ();
3424     transition.finish (this);
3425     runtime->init ();
3426     Mrl::deactivate ();
3427     (void) surface ();
3428     region_node = 0L;
3429     postpone_lock = 0L;
3430 }
3431 
3432 KDE_NO_EXPORT void SMIL::MediaType::defer () {
3433     if (media_info) {
3434         //media_info->pause ();
3435         bool running = unfinished ();
3436         setState (state_deferred);
3437         if (running)
3438             postpone_lock = document ()->postpone ();
3439     }
3440 }
3441 
3442 KDE_NO_EXPORT void SMIL::MediaType::undefer () {
3443     if (runtime->started ()) {
3444         setState (state_began);
3445         if (media_info && media_info->media)
3446             media_info->media->unpause ();
3447         Surface *s = surface ();
3448         if (s)
3449             s->repaint ();
3450     } else {
3451         setState (state_activated);
3452     }
3453     postpone_lock = 0L;
3454 }
3455 
3456 KDE_NO_EXPORT void SMIL::MediaType::begin () {
3457     if (!src.isEmpty () && !media_info)
3458         prefetch ();
3459     if (media_info && media_info->downloading ()) {
3460         postpone_lock = document ()->postpone ();
3461         state = state_began;
3462         return; // wait for MsgMediaReady
3463     }
3464 
3465     SMIL::RegionBase *r = findRegion (this, param (Ids::attr_region));
3466     transition.cancelTimer (this); // eg transOut and we're repeating
3467     for (NodePtr c = firstChild (); c; c = c->nextSibling ())
3468         if (SMIL::id_node_param != c->id && c != external_tree)
3469             c->activate (); // activate set/animate.. children
3470     if (r) {
3471         region_node = r;
3472         region_attach.connect (r, MsgSurfaceAttach, this);
3473         r->repaint ();
3474         clipStart ();
3475         transition.begin (this, runtime);
3476     } else {
3477         kWarning () << nodeName() << "::begin " << src << " region '" <<
3478             param (Ids::attr_region) << "' not found" << endl;
3479     }
3480     Element::begin ();
3481 }
3482 
3483 KDE_NO_EXPORT void SMIL::MediaType::clipStart () {
3484     if (region_node && region_node->role (RoleDisplay)) {
3485         if (external_tree)
3486             external_tree->activate ();
3487         else if (media_info && media_info->media)
3488             media_info->media->play ();
3489     }
3490 }
3491 
3492 KDE_NO_EXPORT void SMIL::MediaType::clipStop () {
3493     if (runtime->timingstate == Runtime::timings_stopped) {
3494         region_attach.disconnect ();
3495         if (media_info && media_info->media)
3496             media_info->media->stop ();
3497         if (external_tree && external_tree->active ())
3498             external_tree->deactivate ();
3499     }
3500     if (sub_surface)
3501         sub_surface->repaint ();
3502     document_postponed.disconnect ();
3503 }
3504 
3505 KDE_NO_EXPORT void SMIL::MediaType::finish () {
3506     transition.transition_updater.disconnect ();
3507     if (media_info && media_info->media)
3508         media_info->media->pause ();
3509     postpone_lock = 0L;
3510 
3511     Surface *s = surface ();
3512     if (s)
3513         s->repaint ();
3514     runtime->finish ();
3515 }
3516 
3517 KDE_NO_EXPORT void SMIL::MediaType::reset () {
3518     Mrl::reset ();
3519     runtime->init ();
3520 }
3521 
3522 KDE_NO_EXPORT SRect SMIL::MediaType::calculateBounds () {
3523     SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
3524     if (rb && rb->role (RoleDisplay)) {
3525         SRect rr = rb->region_surface->bounds;
3526         Single x, y, w = size.width, h = size.height;
3527         sizes.calcSizes (this, &rb->sizes, rr.width(), rr.height(), x, y, w, h);
3528         if (fit_default != fit)
3529             effective_fit = fit;
3530         ImageMedia *im;
3531         switch (effective_fit) {
3532             case fit_scroll:
3533             case fit_default:
3534             case fit_hidden:
3535                 if (media_info &&
3536                         (MediaManager::AudioVideo == media_info->type ||
3537                         (MediaManager::Image == media_info->type &&
3538                          (im = static_cast <ImageMedia *>(media_info->media)) &&
3539                          !im->isEmpty () &&
3540                          im->cached_img->flags & ImageData::ImageScalable)))
3541                     effective_fit = fit_meet;
3542                 break;
3543             default:
3544                 break;
3545         }
3546 
3547         if (!size.isEmpty () && w > 0 && h > 0)
3548             switch (effective_fit) {
3549                 case fit_meet: {
3550                     float iasp = 1.0 * size.width / size.height;
3551                     float rasp = 1.0 * w / h;
3552                     if (iasp > rasp)
3553                         h = size.height * w / size.width;
3554                     else
3555                         w = size.width * h / size.height;
3556                     break;
3557                 }
3558                 case fit_scroll:
3559                 case fit_default:
3560                 case fit_hidden:
3561                      w = size.width;
3562                      h = size.height;
3563                      break;
3564                 case fit_slice: {
3565                     float iasp = 1.0 * size.width / size.height;
3566                     float rasp = 1.0 * w / h;
3567                     if (iasp > rasp)
3568                         w = size.width * h / size.height;
3569                     else
3570                         h = size.height * w / size.width;
3571                     break;
3572                 }
3573                 default: {} // fit_fill
3574             }
3575         return SRect (x, y, w, h);
3576     }
3577     return SRect ();
3578 }
3579 
3580 void SMIL::MediaType::message (MessageType msg, void *content) {
3581     switch (msg) {
3582 
3583         case MsgEventPostponed: {
3584             PostponedEvent *pe = static_cast <PostponedEvent *> (content);
3585             if (media_info) {
3586                 if (pe->is_postponed) {
3587                     if (unfinished ()) {
3588                         setState (state_deferred);
3589                         if (media_info->media)
3590                             media_info->media->pause ();
3591                     }
3592                 } else if (state == Node::state_deferred) {
3593                     setState (state_began);
3594                     if (media_info->media)
3595                         media_info->media->unpause ();
3596                 }
3597             }
3598             return;
3599         }
3600 
3601         case MsgSurfaceBoundsUpdate:
3602             if (sub_surface)
3603                 sub_surface->resize (calculateBounds (), !!content);
3604             return;
3605 
3606         case MsgStateFreeze:
3607             clipStop ();
3608             return;
3609 
3610         case MsgChildFinished: {
3611             Posting *post = (Posting *) content;
3612             if (post->source->mrl () &&
3613                     post->source->mrl ()->opener.ptr () == this) {
3614                 post->source->deactivate (); // should only if fill not is freeze or hold
3615             } else if (active ()) {
3616                 if (runtime->state () < Runtime::timings_stopped) {
3617                     if (runtime->started ())
3618                         runtime->tryFinish (); // what about repeat_count ..
3619                     return; // still running, wait for runtime to finish
3620                 }
3621             }
3622             if (active ())
3623                 finish ();
3624             return;
3625         }
3626 
3627         case MsgStateRewind:
3628             if (external_tree) {
3629                 State old = state;
3630                 state = state_deactivated;
3631                 external_tree->reset ();
3632                 state = old;
3633             }
3634             return;
3635 
3636         case MsgMediaPrefetch:
3637             if (content) {
3638                 init ();
3639                 if (!src.isEmpty () && !media_info)
3640                     prefetch ();
3641             } else if (media_info) {
3642                 delete media_info;
3643                 media_info = NULL;
3644             }
3645             return;
3646 
3647         case MsgMediaReady: {
3648             resolved = true;
3649             Mrl *mrl = external_tree ? external_tree->mrl () : NULL;
3650             if (mrl)
3651                 size = mrl->size;
3652             postpone_lock = 0L;
3653             message (MsgSurfaceBoundsUpdate, (void *) true);
3654             if (state == state_began) {
3655                 begin ();
3656                 runtime->tryFinish ();
3657             } else if (state < state_began && parentNode ()) {
3658                 parentNode ()->message (MsgChildReady, this);
3659             }
3660             return;
3661         }
3662 
3663         case MsgMediaFinished:
3664             if (state_deferred == state && postpone_lock)
3665                 state = state_began;
3666             if (unfinished ()) {
3667                 if (runtime->durTime ().durval == Runtime::DurMedia)
3668                     runtime->durTime ().durval = Runtime::DurTimer;
3669                 if (media_info) {
3670                     delete media_info;
3671                     media_info = NULL;
3672                 }
3673                 postpone_lock = 0L;
3674                 runtime->tryFinish ();
3675             }
3676             return;
3677 
3678         default:
3679             break;
3680     }
3681     if (!transition.handleMessage (this, runtime, surface (), msg, content)) {
3682         if ((int) msg >= (int) Runtime::DurLastDuration)
3683             Mrl::message (msg, content);
3684         else
3685             runtime->message (msg, content);
3686     }
3687 }
3688 
3689 void *SMIL::MediaType::role (RoleType msg, void *content) {
3690     switch (msg) {
3691 
3692     case RoleReady:
3693         return MsgBool (!media_info || !media_info->downloading ());
3694 
3695     case RoleTiming:
3696         return runtime;
3697 
3698     case RoleDisplay:
3699         return surface ();
3700 
3701     case RoleSizer:
3702         return &sizes;
3703 
3704     case RoleChildDisplay: {
3705         Surface *s = NULL;
3706         Mrl *mrl = (Mrl *) content;
3707         if (mrl) {
3708             size = mrl->size;
3709             message (MsgSurfaceBoundsUpdate);
3710             s = surface ();
3711         }
3712         return s;
3713     }
3714 
3715     case RolePlaylist:
3716         return NULL;
3717 
3718     case RoleReceivers: {
3719         MessageType m = (MessageType) (long) content;
3720         ConnectionList *l = mouse_listeners.receivers (m);
3721         if (l)
3722             return l;
3723         if (MsgSurfaceAttach == m)
3724             return &m_MediaAttached;
3725         if (MsgChildTransformedIn == m)
3726             return &transition.m_TransformedIn;
3727     } // fall through
3728 
3729     default:
3730         break;
3731     }
3732     void *response = runtime->role (msg, content);
3733     if (response == MsgUnhandled)
3734         return Mrl::role (msg, content);
3735     return response;
3736 }
3737 
3738 
3739 Surface *SMIL::MediaType::surface () {
3740     if (!runtime->active ()) {
3741         if (sub_surface)
3742             sub_surface->remove ();
3743         sub_surface = NULL;
3744     } else if (!sub_surface && region_node) {
3745         Surface *rs = (Surface *) region_node->role (RoleDisplay);
3746         if (rs) {
3747             sub_surface = rs->createSurface (this, SRect ());
3748             sub_surface->setBackgroundColor (background_color.color);
3749             message (MsgSurfaceBoundsUpdate);
3750         }
3751     }
3752     return sub_surface.ptr ();
3753 }
3754 
3755 //-----------------------------------------------------------------------------
3756 
3757 namespace {
3758     class SvgElement : public Element {
3759         QByteArray tag;
3760         NodePtrW image;
3761 
3762     public:
3763         SvgElement (NodePtr &doc, Node *img, const QByteArray &t, short id=0)
3764             : Element (doc, id), tag (t), image (img) {}
3765 
3766         void parseParam (const TrieString &name, const QString &val) {
3767             setAttribute (name, val);
3768             Mrl *mrl = image ? image->mrl () : NULL;
3769             if (mrl && mrl->media_info &&
3770                     MediaManager::Image == mrl->media_info->type) {
3771                 ImageMedia *im=static_cast<ImageMedia*>(mrl->media_info->media);
3772                 if (im)
3773                     im->updateRender ();
3774             }
3775         }
3776 
3777         Node *childFromTag (const QString & tag) {
3778             return new SvgElement (m_doc, image.ptr (), tag.toLatin1());
3779         }
3780 
3781         const char *nodeName () const {
3782             return tag.constData ();
3783         }
3784     };
3785 }
3786 
3787 KDE_NO_CDTOR_EXPORT
3788 SMIL::RefMediaType::RefMediaType (NodePtr &d, const QByteArray &t)
3789  : SMIL::MediaType (d, t, id_node_ref) {}
3790 
3791 KDE_NO_EXPORT Node *SMIL::RefMediaType::childFromTag (const QString & tag) {
3792     QByteArray ba = tag.toLatin1 ();
3793     const char *taglatin = ba.constData ();
3794     if (!strcmp (taglatin, "imfl"))
3795         return new RP::Imfl (m_doc);
3796     else if (!strcmp (taglatin, "svg"))
3797         return new SvgElement (m_doc, this, ba, id_node_svg);
3798     Node *n = fromXMLDocumentTag (m_doc, tag);
3799     if (n)
3800         return n;
3801     return SMIL::MediaType::childFromTag (tag);
3802 }
3803 
3804 KDE_NO_EXPORT void SMIL::RefMediaType::prefetch () {
3805     if (!src.isEmpty ()) {
3806         Node *n = findChildWithId (this, id_node_svg);
3807         if (n)
3808             removeChild (n);
3809         if (!media_info)
3810             media_info = new MediaInfo (this, MediaManager::Any);
3811         resolved = media_info->wget (absolutePath ());
3812     }
3813 }
3814 
3815 KDE_NO_EXPORT void SMIL::RefMediaType::activate () {
3816     MediaType::activate ();
3817 
3818     if (src.isEmpty () && (!media_info || !media_info->media)) {
3819         Node *n = findChildWithId (this, id_node_svg);
3820         if (n) {
3821             if (!media_info)
3822                 media_info = new MediaInfo (this, MediaManager::Image);
3823             media_info->media = new ImageMedia (this);
3824             message (MsgMediaReady);
3825         }
3826     }
3827 }
3828 
3829 KDE_NO_EXPORT void SMIL::RefMediaType::clipStart () {
3830     if (media_info && media_info->media &&
3831             media_info->media->type () != MediaManager::Image &&
3832             region_node && !external_tree && !src.isEmpty()) {
3833         repeat = runtime->repeat_count == Runtime::DurIndefinite
3834             ? 9998 : runtime->repeat_count;
3835         runtime->repeat_count = 1;
3836         document_postponed.connect (document(), MsgEventPostponed, this);
3837     }
3838     MediaType::clipStart ();
3839 }
3840 
3841 KDE_NO_EXPORT void SMIL::RefMediaType::finish () {
3842     if (media_info && media_info->media &&
3843             media_info->media->type () != MediaManager::Image &&
3844             runtime->durTime ().durval == Runtime::DurMedia)
3845         runtime->durTime ().durval = Runtime::DurTimer;//reset to make this finish
3846     MediaType::finish ();
3847 }
3848 
3849 KDE_NO_EXPORT void SMIL::RefMediaType::begin () {
3850     MediaType::begin ();
3851     if (media_info && media_info->media &&
3852             media_info->media->type () != MediaManager::Image &&
3853             0 == runtime->durTime ().offset &&
3854             Runtime::DurMedia == runtime->endTime ().durval)
3855         runtime->durTime ().durval = Runtime::DurMedia; // duration of clip
3856 }
3857 
3858 KDE_NO_EXPORT void SMIL::RefMediaType::accept (Visitor * v) {
3859     v->visit (this);
3860 }
3861 
3862 void SMIL::RefMediaType::message (MessageType msg, void *content) {
3863     if (media_info &&
3864             media_info->media &&
3865             media_info->media->type () == MediaManager::Image) {
3866         switch (msg) {
3867 
3868         case MsgMediaUpdated: {
3869             Surface *s = surface ();
3870             if (s) {
3871                 s->markDirty ();
3872                 s->repaint ();
3873             }
3874             if (state >= state_finished)
3875                 clipStop ();
3876             return;
3877         }
3878 
3879         case MsgChildFinished:
3880             if (id_node_svg == ((Posting *) content)->source->id)
3881                 return;
3882 
3883         case MsgMediaReady:
3884             if (media_info) {
3885                 ImageMedia *im = static_cast <ImageMedia *> (media_info->media);
3886                 if (im && !im->isEmpty ())
3887                     im->sizes (size);
3888             }
3889             break;
3890 
3891         default:
3892             break;
3893         }
3894     }
3895     MediaType::message (msg, content);
3896 }
3897 
3898 void *SMIL::RefMediaType::role (RoleType msg, void *content)
3899 {
3900     if (RolePlaylist == msg) {
3901         if (caption ().isEmpty () &&
3902                 !src.isEmpty () &&
3903                 !external_tree &&
3904                 (m_type == "video" || m_type == "audio"))
3905             setCaption (src);
3906         return !caption ().isEmpty () ? (PlaylistRole *) this : NULL;
3907     }
3908     return MediaType::role (msg, content);
3909 }
3910 
3911 Node::PlayType SMIL::RefMediaType::playType ()
3912 {
3913     if (media_info && media_info->media)
3914         switch (media_info->media->type ()) {
3915         case MediaManager::AudioVideo:
3916             return play_type_video;
3917         case MediaManager::Image:
3918             return play_type_image;
3919         default:
3920             break;
3921         }
3922     return play_type_unknown;
3923 }
3924 
3925 //-----------------------------------------------------------------------------
3926 
3927 KDE_NO_CDTOR_EXPORT SMIL::TextMediaType::TextMediaType (NodePtr & d)
3928     : SMIL::MediaType (d, "text", id_node_text) {}
3929 
3930 KDE_NO_EXPORT void SMIL::TextMediaType::init () {
3931     if (Runtime::TimingsInitialized > runtime->timingstate) {
3932         font_size = TextMedia::defaultFontSize ();
3933         font_color = 0;
3934         font_name = "sans";
3935         halign = align_left;
3936 
3937         MediaType::init ();
3938     }
3939 }
3940 
3941 KDE_NO_EXPORT void SMIL::TextMediaType::prefetch () {
3942     if (!media_info) {
3943         media_info = new MediaInfo (this, MediaManager::Text);
3944         media_info->wget (absolutePath ());
3945     }
3946 }
3947 
3948 void
3949 SMIL::TextMediaType::parseParam (const TrieString &name, const QString &val) {
3950     if (name == "color" || name == "fontColor") {
3951         font_color = val.isEmpty () ? 0 : rgbFromValue (val);
3952     } else if (name == "fontFace") {
3953         if (val.toLower ().indexOf ("sans" ) < 0)
3954             font_name = "serif";
3955     } else if (name == "font-size" || name == "fontPtSize") {
3956         font_size = val.isEmpty() ? TextMedia::defaultFontSize() : (int)SizeType (val).size ();
3957     } else if (name == "fontSize") {
3958         font_size += val.isEmpty() ? TextMedia::defaultFontSize() : (int)SizeType (val).size ();
3959     } else if (name == "hAlign") {
3960         QByteArray ba = val.toLatin1 ();
3961         const char *cval = ba.constData ();
3962         if (!cval)
3963             halign = align_left;
3964         else if (!strcmp (cval, "center"))
3965             halign = align_center;
3966         else if (!strcmp (cval, "right"))
3967             halign = align_right;
3968         else
3969             halign = align_left;
3970     // TODO: expandTabs fontBackgroundColor fontSize fontStyle fontWeight hAlig vAlign wordWrap
3971     } else {
3972         MediaType::parseParam (name, val);
3973         return;
3974     }
3975     if (sub_surface) {
3976         size = SSize ();
3977         sub_surface->resize (calculateBounds (), true);
3978     }
3979 }
3980 
3981 KDE_NO_EXPORT void SMIL::TextMediaType::accept (Visitor * v) {
3982     v->visit (this);
3983 }
3984 
3985 //-----------------------------------------------------------------------------
3986 
3987 KDE_NO_CDTOR_EXPORT SMIL::Brush::Brush (NodePtr & d)
3988     : SMIL::MediaType (d, "brush", id_node_brush) {}
3989 
3990 KDE_NO_EXPORT void SMIL::Brush::init () {
3991     if (Runtime::TimingsInitialized > runtime->timingstate)
3992         color.init ();
3993     MediaType::init ();
3994 }
3995 
3996 KDE_NO_EXPORT void SMIL::Brush::accept (Visitor * v) {
3997     v->visit (this);
3998 }
3999 
4000 KDE_NO_EXPORT void SMIL::Brush::parseParam (const TrieString &param, const QString &val) {
4001     if (param == "color") {
4002         color.setColor (val);
4003         Surface *s = surface ();
4004         if (s)
4005             s->repaint ();
4006     } else {
4007         MediaType::parseParam (param, val);
4008     }
4009 }
4010 
4011 //-----------------------------------------------------------------------------
4012 
4013 KDE_NO_CDTOR_EXPORT SMIL::SmilText::SmilText (NodePtr &d)
4014  : Element (d, id_node_smil_text),
4015    runtime (new Runtime (this)) {}
4016 
4017 KDE_NO_CDTOR_EXPORT SMIL::SmilText::~SmilText () {
4018     delete runtime;
4019 }
4020 
4021 void SMIL::SmilText::init () {
4022     if (Runtime::TimingsInitialized > runtime->timingstate) {
4023         background_color.init ();
4024         transition.init ();
4025         props.init ();
4026         RegionBase *rb = static_cast<SMIL::RegionBase *> (region_node.ptr ());
4027         if (rb) {
4028             props.mask (rb->font_props);
4029             media_opacity = rb->media_opacity;
4030         } else {
4031             media_opacity.init ();
4032         }
4033         Element::init ();
4034         runtime->initialize ();
4035     }
4036 }
4037 
4038 void SMIL::SmilText::activate () {
4039     SMIL::RegionBase *r = findRegion (this, param (Ids::attr_region));
4040     if (r)
4041         region_node = r;
4042     init (); // sets all attributes
4043     setState (state_activated);
4044     runtime->start ();
4045 }
4046 
4047 void SMIL::SmilText::begin () {
4048     RegionBase *rb = static_cast<SMIL::RegionBase *> (region_node.ptr ());
4049     transition.cancelTimer (this); // eg transOut and we're repeating
4050     if (rb) {
4051         region_attach.connect (rb, MsgSurfaceAttach, this);
4052         rb->repaint ();
4053         transition.begin (this, runtime);
4054     }
4055     setState (state_began);
4056     for (NodePtr c = firstChild (); c; c = c->nextSibling ())
4057         c->activate ();
4058 
4059 }
4060 
4061 void SMIL::SmilText::finish () {
4062     transition.transition_updater.disconnect ();
4063     runtime->finish ();
4064 }
4065 
4066 void SMIL::SmilText::deactivate () {
4067     transition.finish (this);
4068     region_attach.disconnect ();
4069     if (text_surface) {
4070         text_surface->repaint ();
4071         text_surface->remove ();
4072         text_surface = NULL;
4073     }
4074     sizes.resetSizes ();
4075     runtime->init ();
4076     Element::deactivate ();
4077 }
4078 
4079 void SMIL::SmilText::reset () {
4080     runtime->init ();
4081     Element::reset ();
4082 }
4083 
4084 Node *SMIL::SmilText::childFromTag (const QString &tag) {
4085     QByteArray ba = tag.toLatin1 ();
4086     const char *ctag = ba.constData ();
4087     if (!strcmp (ctag, "tev"))
4088         return new TemporalMoment (m_doc, id_node_tev, ba);
4089     if (!strcmp (ctag, "clear"))
4090         return new TemporalMoment (m_doc, id_node_clear, ba);
4091     return fromTextFlowGroup (m_doc, tag);
4092 }
4093 
4094 void SMIL::SmilText::parseParam (const TrieString &name, const QString &value) {
4095     if (props.parseParam (name, value)
4096             || sizes.setSizeParam (name, value)
4097             || parseBackgroundParam (background_color, name, value)
4098             || parseMediaOpacityParam (media_opacity, name, value)) {
4099         message (MsgMediaUpdated);
4100     } else if (!runtime->parseParam (name, value)
4101             && !parseTransitionParam (this, transition, runtime, name, value)) {
4102         Element::parseParam (name, value);
4103     }
4104 }
4105 
4106 void SMIL::SmilText::updateBounds (bool remove) {
4107     if (text_surface) {
4108         SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
4109         Surface *rs = (Surface *) region_node->role (RoleDisplay);
4110         if (rs) {
4111             SRect b = rs->bounds;
4112             Single x, y, w = size.width, h = size.height;
4113             sizes.calcSizes (this, &rb->sizes, b.width(), b.height(), x, y, w, h);
4114             if (!size.isEmpty () && w > 0 && h > 0) {
4115                 w = size.width;
4116                 h = size.height;
4117             }
4118             text_surface->resize (SRect (x, y, w, h), remove);
4119         }
4120     }
4121 }
4122 
4123 void SMIL::SmilText::message (MessageType msg, void *content) {
4124     switch (msg) {
4125 
4126         case MsgSurfaceBoundsUpdate:
4127             updateBounds (!!content);
4128             return;
4129 
4130         case MsgStateFreeze:
4131             if (!runtime->active () && text_surface) {
4132                 text_surface->repaint ();
4133                 text_surface->remove ();
4134                 text_surface = NULL;
4135             }
4136             return;
4137 
4138         case MsgChildFinished:
4139             if (unfinished ())
4140                 runtime->tryFinish ();
4141             return;
4142 
4143         case MsgMediaUpdated:
4144             if (surface ()) {
4145                 text_surface->parentNode ()->repaint ();
4146                 text_surface->remove ();
4147                 text_surface = NULL;
4148             }
4149             return;
4150 
4151         default:
4152             break;
4153     }
4154     if (!transition.handleMessage (this, runtime, surface (), msg, content)) {
4155         if ((int) msg >= (int) Runtime::DurLastDuration)
4156             Element::message (msg, content);
4157         else
4158             runtime->message (msg, content);
4159     }
4160 }
4161 
4162 void *SMIL::SmilText::role (RoleType msg, void *content) {
4163     switch (msg) {
4164 
4165     case RoleTiming:
4166         return runtime;
4167 
4168     case RoleDisplay:
4169         return surface ();
4170 
4171     case RoleSizer:
4172         return &sizes;
4173 
4174     case RoleReceivers: {
4175         MessageType msgt = (MessageType) (long) content;
4176         ConnectionList *l = mouse_listeners.receivers (msgt);
4177         if (l)
4178             return l;
4179         if (MsgSurfaceAttach == msgt)
4180             return &media_attached;
4181         if (MsgChildTransformedIn == msgt)
4182             return &transition.m_TransformedIn;
4183     } // fall through
4184 
4185     default:
4186         break;
4187     }
4188     void *response = runtime->role (msg, content);
4189     if (response == MsgUnhandled)
4190         return Element::role (msg, content);
4191     return response;
4192 }
4193 
4194 Surface *SMIL::SmilText::surface () {
4195     if (!runtime->active ()) {
4196         if (text_surface) {
4197             text_surface->remove ();
4198             text_surface = NULL;
4199         }
4200     } else if (region_node && !text_surface) {
4201         Surface *rs = (Surface *) region_node->role (RoleDisplay);
4202         if (rs) {
4203             text_surface = rs->createSurface (this, SRect ());
4204             text_surface->setBackgroundColor (background_color.color);
4205             size = SSize ();
4206             updateBounds (false);
4207         }
4208     }
4209     return text_surface.ptr ();
4210 }
4211 
4212 //-----------------------------------------------------------------------------
4213 
4214 void SmilTextProperties::init () {
4215     font_color = -1;
4216     background_color = -1;
4217     text_direction = DirInherit;
4218     font_family = "sans";
4219     font_size = -1;
4220     font_style = StyleInherit;
4221     font_weight = WeightInherit;
4222     text_mode = ModeInherit;
4223     text_place = PlaceInherit;
4224     text_style = "";
4225     text_wrap = WrapInherit;
4226     space = SpaceDefault;
4227     text_writing = WritingLrTb;
4228     text_align = AlignInherit;
4229 }
4230 
4231 bool SmilTextProperties::parseParam(const TrieString &name, const QString &val) {
4232     if (name == "textWrap") {
4233         // { Wrap, NoWrap, WrapInherit } text_wrap;
4234     } else if (name == "space" /*xml:space*/) {
4235         // { SpaceDefault, SpacePreserve } space;
4236     } else if (name == "textAlign") {
4237         if (val == "left")
4238             text_align = AlignLeft;
4239         else if (val == "center")
4240             text_align = AlignCenter;
4241         else if (val == "right")
4242             text_align = AlignRight;
4243         // start, end
4244         else
4245             text_align = AlignInherit;
4246     } else if (name == "textBackgroundColor") {
4247         background_color = rgbFromValue (val);
4248     } else if (name == "textColor") {
4249         font_color = rgbFromValue (val);
4250     } else if (name == "textDirection") {
4251         if (val == "ltr")
4252             text_direction = DirLtr;
4253         else if (val == "rtl")
4254             text_direction = DirRtl;
4255         else
4256             text_direction = DirInherit;
4257         //  DirLtro, DirRtlo
4258     } else if (name == "textFontFamily") {
4259         font_family = val;
4260     } else if (name == "textFontSize") {
4261         font_size = SizeType (val);
4262     } else if (name == "textFontStyle") {
4263         if (val == "normal")
4264             font_style = StyleNormal;
4265         else if (val == "italic")
4266             font_style = StyleItalic;
4267         else if (val == "oblique")
4268             font_style = StyleOblique;
4269         else if (val == "reverseOblique")
4270             font_style = StyleRevOblique;
4271         else
4272             font_style = StyleInherit;
4273     } else if (name == "textFontWeight") {
4274         if (val == "normal")
4275             font_weight = WeightNormal;
4276         else if (val == "bold")
4277             font_weight = WeightBold;
4278         else
4279             font_weight = WeightInherit;
4280     } else if (name == "textMode") {
4281         // { ModeAppend, ModeReplace, ModeInherit } text_mode;
4282     } else if (name == "textPlace") {
4283         //enum { PlaceStart, PlaceCenter, PlaceEnd, PlaceInherit } text_place;
4284     } else if (name == "textStyle") {
4285         text_style = val;
4286     } else if (name == "textWritingMode") {
4287         // { WritingLrTb, WritingRlTb, WritingTbLr, WritingTbRl } text_writing;
4288     } else {
4289         return false;
4290     }
4291     return true;
4292 }
4293 
4294 void SmilTextProperties::mask (const SmilTextProperties &props) {
4295     if ((float)props.font_size.size () > 0.1)
4296         font_size = props.font_size;
4297     if (props.font_color > -1)
4298         font_color = props.font_color;
4299     if (props.background_color > -1)
4300         background_color = props.background_color;
4301     if (StyleInherit != props.font_style)
4302         font_style = props.font_style;
4303     if (WeightInherit != props.font_weight)
4304         font_weight = props.font_weight;
4305     if (AlignInherit != props.text_align)
4306         text_align = props.text_align;
4307     font_family = props.font_family;
4308 }
4309 
4310 KDE_NO_CDTOR_EXPORT
4311 SMIL::TextFlow::TextFlow (NodePtr &doc, short id, const QByteArray &t)
4312  : Element (doc, id), tag (t) {}
4313 
4314 KDE_NO_CDTOR_EXPORT SMIL::TextFlow::~TextFlow () {}
4315 
4316 void SMIL::TextFlow::init () {
4317     props.init ();
4318     Element::init ();
4319 }
4320 
4321 void SMIL::TextFlow::activate () {
4322     init ();
4323     Element::activate ();
4324 }
4325 
4326 Node *SMIL::TextFlow::childFromTag (const QString &tag) {
4327     return fromTextFlowGroup (m_doc, tag);
4328 }
4329 
4330 void SMIL::TextFlow::parseParam(const TrieString &name, const QString &val) {
4331     if (!props.parseParam (name, val))
4332         Element::parseParam (name, val);
4333 }
4334 
4335 SMIL::TemporalMoment::TemporalMoment (NodePtr &doc, short id, const QByteArray &t)
4336  : Element (doc, id),
4337    runtime (new Runtime (this)),
4338    tag (t) {}
4339 
4340 SMIL::TemporalMoment::~TemporalMoment () {
4341     delete runtime;
4342 }
4343 
4344 void SMIL::TemporalMoment::init () {
4345     if (Runtime::TimingsInitialized > runtime->timingstate) {
4346         Element::init ();
4347         runtime->initialize ();
4348     }
4349 }
4350 
4351 void SMIL::TemporalMoment::activate () {
4352     init ();
4353     setState (state_activated);
4354     runtime->start ();
4355 }
4356 
4357 void SMIL::TemporalMoment::begin () {
4358     parentNode ()->message (MsgMediaUpdated);
4359     Element::begin ();
4360 }
4361 
4362 void SMIL::TemporalMoment::deactivate () {
4363     runtime->init ();
4364     Element::deactivate ();
4365 }
4366 
4367 Node *SMIL::TemporalMoment::childFromTag (const QString & tag) {
4368     return fromTextFlowGroup (m_doc, tag);
4369 }
4370 
4371 void SMIL::TemporalMoment::parseParam (const TrieString &name, const QString &value) {
4372     // TODO: next
4373     if (!runtime->parseParam (name, value))
4374         Element::parseParam (name, value);
4375 }
4376 
4377 void SMIL::TemporalMoment::message (MessageType msg, void *content) {
4378     if ((int) msg >= (int) Runtime::DurLastDuration)
4379         Element::message (msg, content);
4380     else
4381         runtime->message (msg, content);
4382 }
4383 
4384 void *SMIL::TemporalMoment::role (RoleType msg, void *content) {
4385     if (RoleTiming == msg)
4386         return runtime;
4387     void *response = runtime->role (msg, content);
4388     if (response == MsgUnhandled)
4389         return Element::role (msg, content);
4390     return response;
4391 }
4392 
4393 //-----------------------------------------------------------------------------
4394 
4395 SMIL::StateValue::StateValue (NodePtr &d, short _id)
4396  : Element (d, _id), ref (NULL), runtime (new Runtime (this)) {
4397 }
4398 
4399 SMIL::StateValue::~StateValue () {
4400     delete runtime;
4401     delete ref;
4402 }
4403 
4404 void SMIL::StateValue::init () {
4405     if (Runtime::TimingsInitialized > runtime->timingstate) {
4406         SMIL::Smil *smil = SMIL::Smil::findSmilNode (this);
4407         if (smil)
4408             state = smil->state_node.ptr ();
4409         Element::init ();
4410         runtime->initialize ();
4411     }
4412 }
4413 
4414 void SMIL::StateValue::activate () {
4415     init ();
4416     setState (state_activated);
4417     for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
4418         QString v = a->value ();
4419         int p = v.indexOf ('{');
4420         if (p > -1) {
4421             int q = v.indexOf ('}', p + 1);
4422             if (q > -1)
4423                 parseParam (a->name (), applySubstitution (this, v, p, q));
4424         }
4425     }
4426     runtime->start ();
4427 }
4428 
4429 void SMIL::StateValue::finish () {
4430     runtime->finish ();
4431 }
4432 
4433 void SMIL::StateValue::deactivate () {
4434     if (unfinished ())
4435         finish ();
4436     delete ref;
4437     ref = NULL;
4438     runtime->init ();
4439     Element::deactivate ();
4440 }
4441 
4442 void SMIL::StateValue::reset () {
4443     runtime->init ();
4444     Element::reset ();
4445 }
4446 
4447 void SMIL::StateValue::parseParam (const TrieString &para, const QString &val) {
4448     if (para == Ids::attr_value) {
4449         value = val;
4450     } else if (para == "ref") {
4451         delete ref;
4452         if (state)
4453             ref = evaluateExpr(val.toUtf8(), "data");
4454         else
4455             ref = NULL;
4456     } else if (!runtime->parseParam (para, val)) {
4457         Element::parseParam (para, val);
4458     }
4459 }
4460 
4461 void SMIL::StateValue::message (MessageType msg, void *data) {
4462     if ((int) msg >= (int) Runtime::DurLastDuration)
4463         Element::message (msg, data);
4464     else
4465         runtime->message (msg, data);
4466 }
4467 
4468 void *SMIL::StateValue::role (RoleType msg, void *data) {
4469     switch (msg) {
4470 
4471     case RoleTiming:
4472         return runtime;
4473 
4474     default:
4475         break;
4476     }
4477     void *response = runtime->role (msg, data);
4478     if (response == MsgUnhandled)
4479         return Element::role (msg, data);
4480     return response;
4481 }
4482 
4483 //-----------------------------------------------------------------------------
4484 
4485 void SMIL::NewValue::init () {
4486     where = SMIL::State::child;
4487     StateValue::init ();
4488 }
4489 
4490 void SMIL::NewValue::begin () {
4491     SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4492     if (name.isEmpty () || !st) {
4493         kWarning () << "name is empty or no state";
4494     } else {
4495         if (!ref)
4496             ref = evaluateExpr ("/data");
4497         ref->setRoot (st);
4498         Expression::iterator it = ref->begin(), e = ref->end();
4499         if (it != e && it->node) {
4500             if (name.startsWith(QChar('@')) && it->node->isElementNode())
4501                 static_cast<Element*>(it->node)->setAttribute(name.mid(1), value);
4502             else
4503                 st->newValue(it->node, where, name, value);
4504         }
4505     }
4506 }
4507 
4508 void SMIL::NewValue::parseParam (const TrieString &para, const QString &val) {
4509     if (para == Ids::attr_name)
4510         name = val;
4511     else if (para == "where") {
4512         if (val == "before")
4513             where = SMIL::State::before;
4514         else if (val == "after")
4515             where = SMIL::State::after;
4516         else
4517             where = SMIL::State::child;
4518     } else {
4519         StateValue::parseParam (para, val);
4520     }
4521 }
4522 
4523 //-----------------------------------------------------------------------------
4524 
4525 void SMIL::SetValue::begin () {
4526     SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4527     if (!ref || !st) {
4528         kWarning () << "ref is empty or no state";
4529     } else {
4530         ref->setRoot (st);
4531         Expression::iterator it = ref->begin(), e = ref->end();
4532         if (it != e && it->node) {
4533             if (it->attr && it->node->isElementNode ())
4534                 static_cast<Element*>(it->node)->setAttribute(it->attr->name(), value);
4535             else
4536                 st->setValue(it->node, value);
4537         }
4538     }
4539 }
4540 
4541 //-----------------------------------------------------------------------------
4542 
4543 void SMIL::DelValue::begin () {
4544     SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4545     if (!ref || !st) {
4546         kWarning () << "ref is empty or no state";
4547     } else {
4548         ref->setRoot (st);
4549         Expression::iterator it = ref->begin(), e = ref->end();
4550         while (it != e) {
4551             if (it->attr && it->node->isElementNode ())
4552                 static_cast<Element*>(it->node)->setAttribute(it->attr->name(), QString());
4553             else
4554                 it->node->parentNode()->removeChild(it->node);
4555             ref->setRoot (st);
4556             it = ref->begin();
4557         }
4558     }
4559 }
4560 
4561 //-----------------------------------------------------------------------------
4562 
4563 void SMIL::Send::init () {
4564     method = SMIL::State::get;
4565     replace = SMIL::State::instance;
4566     StateValue::init ();
4567 }
4568 
4569 void SMIL::Send::begin () {
4570     SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4571     if (action.isEmpty () || !st) {
4572         kWarning () << "action is empty or no state";
4573     } else {
4574         Smil *s = SMIL::Smil::findSmilNode (this);
4575         if (s) {
4576             delete media_info;
4577             media_info = new MediaInfo (this, MediaManager::Text);
4578             Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
4579             QString url = mrl ? KURL (mrl->absolutePath(), action).url() : action;
4580             if (SMIL::State::get == method && replace == SMIL::State::instance) {
4581                 // TODO compose GET url
4582                 media_info->wget (url, st->domain ());
4583             } else // TODO ..
4584                 qDebug("unsupported method %d replace %d", method, replace);
4585         }
4586     }
4587 }
4588 
4589 void SMIL::Send::deactivate () {
4590     delete media_info;
4591     media_info = NULL;
4592     action.clear ();
4593     StateValue::deactivate ();
4594 }
4595 
4596 void SMIL::Send::parseParam (const TrieString &para, const QString &val) {
4597     if (para == "action") {
4598         action = val;
4599     } else if (para == "method") {
4600         if (val == "put")
4601             method = SMIL::State::put;
4602         else
4603             method = SMIL::State::get;
4604     } else if (para == "replace") {
4605         if (val == "all")
4606             replace = SMIL::State::all;
4607         else if (val == "none")
4608             replace = SMIL::State::none;
4609         else
4610             replace = SMIL::State::instance;
4611     } else if (para == "target") {
4612         delete ref;
4613         if (state)
4614             ref = evaluateExpr(val.toUtf8(), "data");
4615         else
4616             ref = NULL;
4617     } else {
4618         StateValue::parseParam (para, val);
4619     }
4620 }
4621 
4622 void SMIL::Send::message (MessageType msg, void *content) {
4623     SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4624     switch (msg) {
4625 
4626     case MsgMediaReady: {
4627         Node *target = NULL;
4628         if (!ref && SMIL::State::instance == replace)
4629             ref = evaluateExpr ("/data");
4630         if (ref) {
4631             ref->setRoot (st);
4632             Expression::iterator it = ref->begin(), e = ref->end();
4633             if (it != e)
4634                 target = it->node;
4635         }
4636         if (target) {
4637             Node *parent = target->parentNode ();
4638             Node *next = target->nextSibling ();
4639             bool changed = target->firstChild ();
4640             target->clearChildren ();
4641             if (media_info && media_info->media) {
4642                 QTextStream in (&((TextMedia *)media_info->media)->text);
4643                 readXML (target, in, QString ());
4644                 if (target->firstChild ()) {
4645                     NodePtr store = target->firstChild ();
4646                     parent->removeChild (target);
4647                     parent->insertBefore (store, next);
4648                     target = store;
4649                     changed = true;
4650                 }
4651             }
4652             if (changed)
4653                 st->stateChanged (target);
4654         }
4655         delete media_info;
4656         media_info = NULL;
4657         return;
4658     }
4659     default:
4660         break;
4661     }
4662     StateValue::message (msg, content);
4663 }
4664 
4665 //-----------------------------------------------------------------------------
4666 
4667 KDE_NO_CDTOR_EXPORT SMIL::AnimateGroup::AnimateGroup (NodePtr &d, short _id)
4668  : Element (d, _id),
4669    runtime (new Runtime (this)),
4670    modification_id (-1) {}
4671 
4672 KDE_NO_CDTOR_EXPORT SMIL::AnimateGroup::~AnimateGroup () {
4673     delete runtime;
4674 }
4675 
4676 void SMIL::AnimateGroup::parseParam (const TrieString &name, const QString &val) {
4677     if (name == Ids::attr_target || name == "targetElement") {
4678         target_id = val;
4679     } else if (name == "attribute" || name == "attributeName") {
4680         changed_attribute = TrieString (val);
4681     } else if (name == "to") {
4682         change_to = val;
4683     } else if (!runtime->parseParam (name, val)) {
4684         Element::parseParam (name, val);
4685     }
4686 }
4687 
4688 KDE_NO_EXPORT void SMIL::AnimateGroup::init () {
4689     if (Runtime::TimingsInitialized > runtime->timingstate) {
4690         Element::init ();
4691         runtime->initialize ();
4692     }
4693 }
4694 
4695 KDE_NO_EXPORT void SMIL::AnimateGroup::activate () {
4696     init ();
4697     setState (state_activated);
4698     runtime->start ();
4699 }
4700 
4701 /**
4702  * animation finished
4703  */
4704 KDE_NO_EXPORT void SMIL::AnimateGroup::finish () {
4705     runtime->finish ();
4706 }
4707 
4708 KDE_NO_EXPORT void SMIL::AnimateGroup::reset () {
4709     Element::reset ();
4710     target_id.truncate (0);
4711     runtime->init ();
4712 }
4713 
4714 KDE_NO_EXPORT void SMIL::AnimateGroup::deactivate () {
4715     restoreModification ();
4716     if (unfinished ())
4717         finish ();
4718     runtime->init ();
4719     Element::deactivate ();
4720 }
4721 
4722 KDE_NO_EXPORT void SMIL::AnimateGroup::message (MessageType msg, void *data) {
4723     switch (msg) {
4724 
4725         case MsgStateFreeze:
4726             if (!runtime->active ())
4727                 restoreModification ();
4728             return;
4729 
4730         case MsgStateRewind:
4731             restoreModification ();
4732             return;
4733 
4734         default:
4735             break;
4736     }
4737     if ((int) msg >= (int) Runtime::DurLastDuration)
4738         Element::message (msg, data);
4739     else
4740         runtime->message (msg, data);
4741 }
4742 
4743 KDE_NO_EXPORT void *SMIL::AnimateGroup::role (RoleType msg, void *data) {
4744     switch (msg) {
4745 
4746     case RoleTiming:
4747         return runtime;
4748 
4749     default:
4750         break;
4751     }
4752     void *response = runtime->role (msg, data);
4753     if (response == MsgUnhandled)
4754         return Element::role (msg, data);
4755     return response;
4756 }
4757 
4758 
4759 KDE_NO_EXPORT void SMIL::AnimateGroup::restoreModification () {
4760     if (modification_id > -1 && target_element &&
4761             target_element->state > Node::state_init) {
4762         convertNode <Element> (target_element)->resetParam (
4763                 changed_attribute, modification_id);
4764     }
4765     modification_id = -1;
4766 }
4767 
4768 KDE_NO_EXPORT Node *SMIL::AnimateGroup::targetElement () {
4769     if (target_id.isEmpty ()) {
4770         for (Node *p = parentNode(); p; p =p->parentNode())
4771             if (SMIL::id_node_first_mediatype <= p->id &&
4772                     SMIL::id_node_last_mediatype >= p->id) {
4773                 target_element = p;
4774                 break;
4775             }
4776     } else {
4777         target_element = findLocalNodeById (this, target_id);
4778     }
4779     return target_element.ptr ();
4780 }
4781 
4782 //-----------------------------------------------------------------------------
4783 
4784 KDE_NO_EXPORT void SMIL::Set::begin () {
4785     restoreModification ();
4786     Element *target = static_cast <Element *> (targetElement ());
4787     if (target)
4788         target->setParam (changed_attribute, change_to, &modification_id);
4789     else
4790         kWarning () << "target element not found" << endl;
4791     AnimateGroup::begin ();
4792 }
4793 
4794 //-----------------------------------------------------------------------------
4795 /*
4796 //http://en.wikipedia.org/wiki/B%C3%A9zier_curve
4797 typedef struct {
4798     float x;
4799     float y;
4800 } Point2D;
4801 
4802 static Point2D PointOnCubicBezier (Point2D *cp, float t) {
4803     float   ax, bx, cx;
4804     float   ay, by, cy;
4805     float   tSquared, tCubed;
4806     Point2D result;
4807 
4808     // calculate the polynomial coefficients
4809 
4810     cx = 3.0 * (cp[1].x - cp[0].x);
4811     bx = 3.0 * (cp[2].x - cp[1].x) - cx;
4812     ax = cp[3].x - cp[0].x - cx - bx;
4813 
4814     cy = 3.0 * (cp[1].y - cp[0].y);
4815     by = 3.0 * (cp[2].y - cp[1].y) - cy;
4816     ay = cp[3].y - cp[0].y - cy - by;
4817 
4818     // calculate the curve point at parameter value t
4819 
4820     tSquared = t * t;
4821     tCubed = tSquared * t;
4822 
4823     result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
4824     result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
4825 
4826     return result;
4827 }
4828 */
4829 
4830 KDE_NO_CDTOR_EXPORT SMIL::AnimateBase::AnimateBase (NodePtr &d, short id)
4831  : AnimateGroup (d, id),
4832    anim_timer (NULL),
4833    keytimes (NULL),
4834    spline_table (NULL),
4835    keytime_count (0) {}
4836 
4837 KDE_NO_CDTOR_EXPORT SMIL::AnimateBase::~AnimateBase () {
4838     if (keytimes)
4839         free (keytimes);
4840     if (spline_table)
4841         free (spline_table);
4842 }
4843 
4844 KDE_NO_EXPORT void SMIL::AnimateBase::init () {
4845     if (Runtime::TimingsInitialized > runtime->timingstate) {
4846         if (anim_timer) {
4847             document ()->cancelPosting (anim_timer);
4848             anim_timer = NULL;
4849         }
4850         accumulate = acc_none;
4851         additive = add_replace;
4852         calcMode = calc_linear;
4853         change_from.truncate (0);
4854         change_by.truncate (0);
4855         values.clear ();
4856         if (keytimes)
4857             free (keytimes);
4858         keytimes = NULL;
4859         keytime_count = 0;
4860         if (spline_table)
4861             free (spline_table);
4862         spline_table = NULL;
4863         splines.clear ();
4864         AnimateGroup::init ();
4865     }
4866 }
4867 
4868 KDE_NO_EXPORT void SMIL::AnimateBase::begin () {
4869     interval = 0;
4870     if (!setInterval ())
4871         return;
4872     applyStep ();
4873     if (calc_discrete != calcMode)
4874         change_updater.connect (m_doc, MsgSurfaceUpdate, this);
4875     AnimateGroup::begin ();
4876 }
4877 
4878 KDE_NO_EXPORT void SMIL::AnimateBase::finish () {
4879     if (anim_timer) { // make sure timers are stopped
4880         document ()->cancelPosting (anim_timer);
4881         anim_timer = NULL;
4882     }
4883     change_updater.disconnect ();
4884     AnimateGroup::finish ();
4885 }
4886 
4887 KDE_NO_EXPORT void SMIL::AnimateBase::deactivate () {
4888     if (anim_timer) {
4889         document ()->cancelPosting (anim_timer);
4890         anim_timer = NULL;
4891     } else {
4892         change_updater.disconnect ();
4893     }
4894     if (spline_table)
4895         free (spline_table);
4896     spline_table = NULL;
4897     AnimateGroup::deactivate ();
4898 }
4899 
4900 KDE_NO_EXPORT void SMIL::AnimateBase::message (MessageType msg, void *data) {
4901     switch (msg) {
4902         case MsgEventTimer: {
4903             TimerPosting *te = static_cast <TimerPosting *> (data);
4904             if (te->event_id == anim_timer_id) {
4905                 anim_timer = NULL;
4906                 timerTick (0);
4907                 return;
4908             }
4909             break;
4910         }
4911         case MsgSurfaceUpdate: {
4912             UpdateEvent *ue = static_cast <UpdateEvent *> (data);
4913             interval_start_time += ue->skipped_time;
4914             interval_end_time += ue->skipped_time;
4915             timerTick (ue->cur_event_time);
4916             return;
4917         }
4918         case MsgStateRewind:
4919             restoreModification ();
4920             if (anim_timer) {
4921                 document ()->cancelPosting (anim_timer);
4922                 anim_timer = NULL;
4923             } else {
4924                 change_updater.disconnect ();
4925             }
4926             break;
4927         default:
4928             break;
4929     }
4930     AnimateGroup::message (msg, data);
4931 }
4932 
4933 void SMIL::AnimateBase::parseParam (const TrieString &name, const QString &val) {
4934     if (name == "from") {
4935         change_from = val;
4936     } else if (name == "by" || name == "change_by") {
4937         change_by = val;
4938     } else if (name == "values") {
4939         values = val.split (QChar (';'));
4940     } else if (name == "keyTimes") {
4941         QStringList kts = val.split (QChar (';'));
4942         if (keytimes)
4943             free (keytimes);
4944         keytime_count = kts.size ();
4945         if (0 == keytime_count) {
4946             keytimes = NULL;
4947             return;
4948         }
4949         keytimes = (float *) malloc (sizeof (float) * keytime_count);
4950         for (unsigned int i = 0; i < keytime_count; i++) {
4951             keytimes[i] = kts[i].trimmed().toDouble();
4952             if (keytimes[i] < 0.0 || keytimes[i] > 1.0)
4953                 kWarning() << "animateMotion wrong keyTimes values";
4954             else if (i == 0 && keytimes[i] > 0.01)
4955                 kWarning() << "animateMotion first keyTimes value not 0";
4956             else
4957                 continue;
4958             free (keytimes);
4959             keytimes = NULL;
4960             keytime_count = 0;
4961             return;
4962         }
4963     } else if (name == "keySplines") {
4964         splines = val.split (QChar (';'));
4965     } else if (name == "calcMode") {
4966         if (val == QString::fromLatin1 ("discrete"))
4967             calcMode = calc_discrete;
4968         else if (val == QString::fromLatin1 ("linear"))
4969             calcMode = calc_linear;
4970         else if (val == QString::fromLatin1 ("paced"))
4971             calcMode = calc_paced;
4972         else if (val == QString::fromLatin1 ("spline"))
4973             calcMode = calc_spline;
4974     } else
4975         AnimateGroup::parseParam (name, val);
4976 }
4977 
4978 static SMIL::AnimateBase::Point2D cubicBezier (float ax, float bx, float cx,
4979         float ay, float by, float cy, float t) {
4980     float   tSquared, tCubed;
4981     SMIL::AnimateBase::Point2D result;
4982 
4983     /* calculate the curve point at parameter value t */
4984 
4985     tSquared = t * t;
4986     tCubed = tSquared * t;
4987 
4988     result.x = (ax * tCubed) + (bx * tSquared) + (cx * t);
4989     result.y = (ay * tCubed) + (by * tSquared) + (cy * t);
4990 
4991     return result;
4992 }
4993 
4994 static
4995 float cubicBezier (SMIL::AnimateBase::Point2D *table, int a, int b, float x) {
4996     if (b > a + 1) {
4997         int mid = (a + b) / 2;
4998         if (table[mid].x > x)
4999             return cubicBezier (table, a, mid, x);
5000         else
5001             return cubicBezier (table, mid, b, x);
5002     }
5003     return table[a].y + (x - table[a].x) / (table[b].x - table[a].x) * (table[b].y - table[a].y);
5004 }
5005 
5006 
5007 bool SMIL::AnimateBase::setInterval () {
5008     int cs = runtime->durTime ().offset;
5009     if (keytime_count > interval + 1)
5010         cs = (int) (cs * (keytimes[interval+1] - keytimes[interval]));
5011     else if (keytime_count > interval && calc_discrete == calcMode)
5012         cs = (int) (cs * (1.0 - keytimes[interval]));
5013     else if (values.size () > 0 && calc_discrete == calcMode)
5014         cs /= values.size ();
5015     else if (values.size () > 1)
5016         cs /= values.size () - 1;
5017     if (cs < 0) {
5018         kWarning () << "animateMotion has no valid duration interval " <<
5019             interval << endl;
5020         runtime->doFinish ();
5021         return false;
5022     }
5023     interval_start_time = document ()->last_event_time;
5024     interval_end_time = interval_start_time + 10 * cs;
5025     switch (calcMode) {
5026         case calc_paced: // FIXME
5027         case calc_linear:
5028             break;
5029         case calc_spline:
5030             if (splines.size () > (int)interval) {
5031                 QStringList kss = splines[interval].split (QChar (' '));
5032                 control_point[0] = control_point[1] = 0;
5033                 control_point[2] = control_point[3] = 1;
5034                 if (kss.size () == 4) {
5035                     for (int i = 0; i < 4; ++i) {
5036                         control_point[i] = kss[i].toDouble();
5037                         if (control_point[i] < 0 || control_point[i] > 1) {
5038                             kWarning () << "keySplines values not between 0-1"
5039                                 << endl;
5040                             control_point[i] = i > 1 ? 1 : 0;
5041                             break;
5042                         }
5043                     }
5044                     if (spline_table)
5045                         free (spline_table);
5046                     spline_table = (Point2D *) malloc (100 * sizeof (Point2D));
5047 
5048                     /* calculate the polynomial coefficients */
5049                     float ax, bx, cx;
5050                     float ay, by, cy;
5051                     cx = 3.0 * control_point[0];
5052                     bx = 3.0 * (control_point[2] - control_point[0]) - cx;
5053                     ax = 1.0 - cx - bx;
5054 
5055                     cy = 3.0 * control_point[1];
5056                     by = 3.0 * (control_point[3] - control_point[1]) - cy;
5057                     ay = 1.0 - cy - by;
5058 
5059                     for (int i = 0; i < 100; ++i)
5060                         spline_table[i] = cubicBezier (ax, bx, cx, ay, by, cy, 1.0*i/100);
5061                 } else {
5062                     kWarning () << "keySplines " << interval <<
5063                         " has not 4 values" << endl;
5064                 }
5065             }
5066             break;
5067         case calc_discrete:
5068             anim_timer = document ()->post (this,
5069                     new TimerPosting (10 * cs, anim_timer_id));
5070             break;
5071         default:
5072             break;
5073     }
5074     //kDebug() << "setInterval " << steps << " " <<
5075     //    cur_x.size () << "," << cur_y.size () << "=>"
5076     //    << end_x.size () << "," << end_y.size () << " d:" << 
5077     //    delta_x.size () << "," << delta_y.size () << endl;
5078     return true;
5079 }
5080 
5081 //-----------------------------------------------------------------------------
5082 
5083 SMIL::Animate::Animate (NodePtr &doc)
5084  : AnimateBase (doc, id_node_animate),
5085    num_count (0), begin_(NULL), cur (NULL), delta (NULL), end (NULL) {
5086 }
5087 
5088 KDE_NO_EXPORT void SMIL::Animate::init () {
5089     if (Runtime::TimingsInitialized > runtime->timingstate) {
5090         cleanUp ();
5091         AnimateBase::init ();
5092     }
5093 }
5094 
5095 KDE_NO_EXPORT void SMIL::Animate::cleanUp () {
5096     if (anim_timer) {
5097         document ()->cancelPosting (anim_timer);
5098         anim_timer = NULL;
5099     }
5100     delete [] begin_;
5101     delete [] cur;
5102     delete [] delta;
5103     delete [] end;
5104     begin_ = cur = delta = end = NULL;
5105     num_count = 0;
5106 }
5107 
5108 KDE_NO_EXPORT void SMIL::Animate::deactivate () {
5109     cleanUp ();
5110     AnimateBase::deactivate ();
5111 }
5112 
5113 KDE_NO_EXPORT void SMIL::Animate::begin () {
5114     restoreModification ();
5115     cleanUp (); // FIXME: repeating doesn't reinit
5116 
5117     NodePtr protect = target_element;
5118     Element *target = static_cast <Element *> (targetElement ());
5119     if (!target) {
5120         kWarning () << "target element not found";
5121         runtime->doFinish ();
5122         return;
5123     }
5124     if (values.size () < 2) {
5125         values.push_front (change_from.isEmpty ()
5126                 ? target->param (changed_attribute)
5127                 : change_from);
5128         if (!change_to.isEmpty ()) {
5129             values.push_back (change_to);
5130         } else if (!change_by.isEmpty ()) {
5131             SizeType b (values[0]);
5132             b += SizeType (change_by);
5133             values.push_back (b.toString ());
5134         }
5135     }
5136     if (values.size () < 2) {
5137         kWarning () << "could not determine change values";
5138         runtime->doFinish ();
5139         return;
5140     }
5141     if (calcMode != calc_discrete) {
5142         QStringList bnums = values[0].split (QString (","));
5143         QStringList enums = values[1].split (QString (","));
5144         num_count = bnums.size ();
5145         if (num_count) {
5146             begin_ = new SizeType [num_count];
5147             end = new SizeType [num_count];
5148             cur = new SizeType [num_count];
5149             delta = new SizeType [num_count];
5150             for (int i = 0; i < num_count; ++i) {
5151                 begin_[i] = bnums[i];
5152                 end[i] = i < enums.size () ? enums[i] : bnums[i];
5153                 cur[i] = begin_[i];
5154                 delta[i] = end[i];
5155                 delta[i] -= begin_[i];
5156             }
5157         }
5158     }
5159     AnimateBase::begin ();
5160 }
5161 
5162 KDE_NO_EXPORT void SMIL::Animate::finish () {
5163     if (active () && calc_discrete != calcMode)
5164         for (int i = 0; i < num_count; ++i)
5165             if (cur[i].size () != end[i].size ()) {
5166                 for (int j = 0; j < num_count; ++j)
5167                     cur[j] = end[j];
5168                 applyStep (); // we lost some steps ..
5169                 break;
5170             }
5171     AnimateBase::finish ();
5172 }
5173 
5174 KDE_NO_EXPORT void SMIL::Animate::applyStep () {
5175     Element *target = convertNode <Element> (target_element);
5176     if (target) {
5177         if (calcMode != calc_discrete) {
5178             if (num_count) {
5179                 QString val (cur[0].toString ());
5180                 for (int i = 1; i < num_count; ++i)
5181                     val += QChar (',') + cur[i].toString ();
5182                 target->setParam (changed_attribute, val, &modification_id);
5183             }
5184         } else if ((int)interval < values.size ()) {
5185             target->setParam (changed_attribute,
5186                     values[interval], &modification_id);
5187         }
5188     }
5189 }
5190 
5191 KDE_NO_EXPORT bool SMIL::Animate::timerTick (unsigned int cur_time) {
5192     if (cur_time && cur_time <= interval_end_time) {
5193         float gain = 1.0 * (cur_time - interval_start_time) /
5194                            (interval_end_time - interval_start_time);
5195         if (gain > 1.0) {
5196             change_updater.disconnect ();
5197             gain = 1.0;
5198         }
5199         switch (calcMode) {
5200             case calc_paced: // FIXME
5201             case calc_linear:
5202                 break;
5203             case calc_spline:
5204                 if (spline_table)
5205                     gain = cubicBezier (spline_table, 0, 99, gain);
5206                 break;
5207             case calc_discrete:
5208                 return false; // shouldn't come here
5209         }
5210         for (int i = 0; i < num_count; ++i) {
5211             cur[i] = delta[i];
5212             cur[i] *= gain;
5213             cur[i] += begin_[i];
5214         }
5215         applyStep ();
5216         return true;
5217     } else if (values.size () > (int) ++interval) {
5218         if (calc_discrete != calcMode) {
5219             if (values.size () <= (int) interval + 1)
5220                 return false;
5221             QStringList enums = values[interval+1].split (QString (","));
5222             for (int i = 0; i < num_count; ++i) {
5223                 begin_[i] = end[i];
5224                 if (i < enums.size ())
5225                     end[i] = enums[i];
5226                 cur[i] = begin_[i];
5227                 delta[i] = end[i];
5228                 delta[i] -= begin_[i];
5229             }
5230         }
5231         if (setInterval ()) {
5232             applyStep ();
5233             return true;
5234         }
5235     }
5236     return false;
5237 }
5238 
5239 //-----------------------------------------------------------------------------
5240 
5241 static
5242 bool getMotionCoordinates (const QString &coord, SizeType &x, SizeType &y) {
5243     int p = coord.indexOf (QChar (','));
5244     if (p < 0)
5245         p = coord.indexOf (QChar (' '));
5246     if (p > 0) {
5247         x = coord.left (p).trimmed ();
5248         y = coord.mid (p + 1).trimmed ();
5249         return true;
5250     }
5251     return false;
5252 }
5253 
5254 KDE_NO_EXPORT void SMIL::AnimateMotion::init () {
5255     cur_x = cur_y = delta_x = delta_y = SizeType();
5256     AnimateBase::init ();
5257 }
5258 
5259 KDE_NO_EXPORT void SMIL::AnimateMotion::begin () {
5260     Node *t = targetElement ();
5261     CalculatedSizer *sizes = t ? (CalculatedSizer *) t->role (RoleSizer) : NULL;
5262     if (!sizes)
5263         return;
5264     old_sizes = *sizes;
5265     if (anim_timer) {
5266         document ()->cancelPosting (anim_timer);
5267         anim_timer = NULL;
5268     }
5269     if (change_from.isEmpty ()) {
5270         if (values.size () > 1) {
5271             getMotionCoordinates (values[0], begin_x, begin_y);
5272             getMotionCoordinates (values[1], end_x, end_y);
5273         } else {
5274             if (sizes->left.isSet ()) {
5275                 begin_x = sizes->left;
5276             } else if (sizes->right.isSet() && sizes->width.isSet ()) {
5277                 begin_x = sizes->right;
5278                 begin_x -= sizes->width;
5279             } else {
5280                 begin_x = "0";
5281             }
5282             if (sizes->top.isSet ()) {
5283                 begin_y = sizes->top;
5284             } else if (sizes->bottom.isSet() && sizes->height.isSet ()) {
5285                 begin_y = sizes->bottom;
5286                 begin_y -= sizes->height;
5287             } else {
5288                 begin_y = "0";
5289             }
5290         }
5291     } else {
5292         getMotionCoordinates (change_from, begin_x, begin_y);
5293     }
5294     if (!change_by.isEmpty ()) {
5295         getMotionCoordinates (change_by, delta_x, delta_y);
5296         end_x = begin_x;
5297         end_y = begin_y;
5298         end_x += delta_x;
5299         end_y += delta_y;
5300     } else if (!change_to.isEmpty ()) {
5301         getMotionCoordinates (change_to, end_x, end_y);
5302     }
5303     cur_x = begin_x;
5304     cur_y = begin_y;
5305     delta_x = end_x;
5306     delta_x -= begin_x;
5307     delta_y = end_y;
5308     delta_y -= begin_y;
5309     AnimateBase::begin ();
5310 }
5311 
5312 KDE_NO_EXPORT void SMIL::AnimateMotion::finish () {
5313     if (active ()) {
5314         if (calcMode != calc_discrete &&
5315                 (cur_x.size () != end_x.size () ||
5316                  cur_y.size () != end_y.size ())) {
5317             cur_x = end_x;
5318             cur_y = end_y;
5319             applyStep (); // we lost some steps ..
5320         }
5321     }
5322     AnimateBase::finish ();
5323 }
5324 
5325 KDE_NO_EXPORT void SMIL::AnimateMotion::restoreModification () {
5326     Node *n = target_element.ptr ();
5327     CalculatedSizer *sizes = n ? (CalculatedSizer *) n->role (RoleSizer) : NULL;
5328     if (sizes) {
5329         *sizes = old_sizes;
5330         n->message (MsgSurfaceBoundsUpdate);
5331     }
5332 }
5333 
5334 KDE_NO_EXPORT void SMIL::AnimateMotion::applyStep () {
5335     Node *n = target_element.ptr ();
5336     CalculatedSizer *sizes = n ? (CalculatedSizer *) n->role (RoleSizer) : NULL;
5337     if (n->role (RoleDisplay)) {
5338         sizes->move (cur_x, cur_y);
5339         n->message (MsgSurfaceBoundsUpdate);
5340     }
5341 }
5342 
5343 KDE_NO_EXPORT bool SMIL::AnimateMotion::timerTick (unsigned int cur_time) {
5344     if (cur_time && cur_time <= interval_end_time) {
5345         float gain = 1.0 * (cur_time - interval_start_time) /
5346                            (interval_end_time - interval_start_time);
5347         if (gain > 1.0) {
5348             change_updater.disconnect ();
5349             gain = 1.0;
5350         }
5351         switch (calcMode) {
5352             case calc_paced: // FIXME
5353             case calc_linear:
5354                 break;
5355             case calc_spline:
5356                 if (spline_table)
5357                     gain = cubicBezier (spline_table, 0, 99, gain);
5358                 break;
5359             case calc_discrete:
5360                 return false; // shouldn't come here
5361         }
5362         cur_x = delta_x;
5363         cur_y = delta_y;
5364         cur_x *= gain;
5365         cur_y *= gain;
5366         cur_x += begin_x;
5367         cur_y += begin_y;
5368         applyStep ();
5369         return true;
5370     } else if (values.size () > (int) ++interval) {
5371         getMotionCoordinates (values[interval], begin_x, begin_y);
5372         cur_x = begin_x;
5373         cur_y = begin_y;
5374         if (calcMode != calc_discrete && values.size () > (int) interval + 1) {
5375             getMotionCoordinates (values[interval+1], end_x, end_y);
5376             delta_x = end_x;
5377             delta_x -= begin_x;
5378             delta_y = end_y;
5379             delta_y -= begin_y;
5380         }
5381         if (setInterval ()) {
5382             applyStep ();
5383             return true;
5384         }
5385     }
5386     return false;
5387 }
5388 
5389 //-----------------------------------------------------------------------------
5390 
5391 static bool getAnimateColor (unsigned int val, SMIL::AnimateColor::Channels &c) {
5392     c.alpha = val >> 24;
5393     c.red = (val >> 16) & 0xff;
5394     c.green = (val >> 8) & 0xff;
5395     c.blue = val & 0xff;
5396     return true;
5397 }
5398 
5399 static bool getAnimateColor (const QString &val, SMIL::AnimateColor::Channels &c) {
5400     if (val.isEmpty ())
5401         return getAnimateColor (0, c);
5402     QColor color (val);
5403     return getAnimateColor (color.rgba (), c);
5404 }
5405 
5406 static short colorNormalise (int c) {
5407     if (c > 255)
5408         return 255;
5409     if (c < -255)
5410         return -255;
5411     return c;
5412 }
5413 
5414 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator *= (const float f) {
5415     alpha = colorNormalise ((int) (f * alpha));
5416     red = colorNormalise ((int) (f * red));
5417     green = colorNormalise ((int) (f * green));
5418     blue = colorNormalise ((int) (f * blue));
5419     return *this;
5420 }
5421 
5422 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator += (const Channels &c) {
5423     alpha = colorNormalise ((int) alpha + c.alpha);
5424     red = colorNormalise ((int) red + c.red);
5425     green = colorNormalise ((int) green + c.green);
5426     blue = colorNormalise ((int) blue + c.blue);
5427     return *this;
5428 }
5429 
5430 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator -= (const Channels &c) {
5431     alpha = colorNormalise ((int) alpha - c.alpha);
5432     red = colorNormalise ((int) red - c.red);
5433     green = colorNormalise ((int) green - c.green);
5434     blue = colorNormalise ((int) blue - c.blue);
5435     return *this;
5436 }
5437 
5438 unsigned int SMIL::AnimateColor::Channels::argb () {
5439     unsigned int v =
5440         (0xff000000 & ((unsigned)(alpha < 0 ? 0 : alpha) << 24)) |
5441         (0x00ff0000 & ((unsigned)(red < 0 ? 0 : red) << 16)) |
5442         (0x0000ff00 & ((unsigned)(green < 0 ? 0 : green) << 8)) |
5443         (0x000000ff & (blue < 0 ? 0 : blue));
5444     return v;
5445 }
5446 
5447 void SMIL::AnimateColor::Channels::clear () {
5448     alpha = red = blue = green = 0;
5449 }
5450 
5451 KDE_NO_EXPORT void SMIL::AnimateColor::init () {
5452     cur_c.clear ();
5453     delta_c.clear ();
5454     changed_attribute = "background-color";
5455     AnimateBase::init ();
5456 }
5457 
5458 KDE_NO_EXPORT void SMIL::AnimateColor::begin () {
5459     Element *target = static_cast <Element *> (targetElement ());
5460     if (!target)
5461         return;
5462     if (anim_timer) {
5463         document ()->cancelPosting (anim_timer);
5464         anim_timer = NULL;
5465     }
5466     if (change_from.isEmpty ()) {
5467         if (values.size () > 1) {
5468             getAnimateColor (values[0], begin_c);
5469             getAnimateColor (values[1], end_c);
5470         } else {
5471             getAnimateColor (target->param (changed_attribute), begin_c);
5472         }
5473     } else {
5474         getAnimateColor (change_from, begin_c);
5475     }
5476     if (!change_by.isEmpty ()) {
5477         getAnimateColor (change_by, delta_c);
5478         end_c = begin_c;
5479         end_c += delta_c;
5480     } else if (!change_to.isEmpty ()) {
5481         getAnimateColor (change_to, end_c);
5482     }
5483     cur_c = begin_c;
5484     delta_c = end_c;
5485     delta_c -= begin_c;
5486     AnimateBase::begin ();
5487 }
5488 
5489 KDE_NO_EXPORT void SMIL::AnimateColor::finish () {
5490     if (active ()) {
5491         if (calcMode != calc_discrete && cur_c.argb () != end_c.argb ()) {
5492             cur_c = end_c;
5493             applyStep (); // we lost some steps ..
5494         }
5495     }
5496     AnimateBase::finish ();
5497 }
5498 
5499 KDE_NO_EXPORT void SMIL::AnimateColor::applyStep () {
5500     Node *target = target_element.ptr ();
5501     if (target) {
5502         QString val; // TODO make more efficient
5503         val.sprintf ("#%08x", cur_c.argb ());
5504         static_cast <Element *> (target)->setParam (changed_attribute, val);
5505     }
5506 }
5507 
5508 KDE_NO_EXPORT bool SMIL::AnimateColor::timerTick (unsigned int cur_time) {
5509     if (cur_time && cur_time <= interval_end_time) {
5510         float gain = 1.0 * (cur_time - interval_start_time) /
5511                            (interval_end_time - interval_start_time);
5512         if (gain > 1.0) {
5513             change_updater.disconnect ();
5514             gain = 1.0;
5515         }
5516         switch (calcMode) {
5517             case calc_paced: // FIXME
5518             case calc_linear:
5519                 break;
5520             case calc_spline:
5521                 if (spline_table)
5522                     gain = cubicBezier (spline_table, 0, 99, gain);
5523                 break;
5524             case calc_discrete:
5525                 return true; // shouldn't come here
5526         }
5527         cur_c = delta_c;
5528         cur_c *= gain;
5529         cur_c += begin_c;
5530         applyStep ();
5531         return true;
5532     } else if (values.size () > (int) ++interval) {
5533         getAnimateColor (values[interval], begin_c);
5534         cur_c = begin_c;
5535         if (calcMode != calc_discrete && values.size () > (int) interval + 1) {
5536             getAnimateColor (values[interval+1], end_c);
5537             delta_c = end_c;
5538             delta_c -= begin_c;
5539         }
5540         if (setInterval ()) {
5541             applyStep ();
5542             return true;
5543         }
5544     }
5545     return false;
5546 }
5547 
5548 //-----------------------------------------------------------------------------
5549 
5550 KDE_NO_EXPORT void SMIL::Param::activate () {
5551     setState (state_activated);
5552     QString name = getAttribute (Ids::attr_name);
5553     Node * parent = parentNode ();
5554     if (!name.isEmpty () && parent && parent->isElementNode ())
5555         static_cast<Element*>(parent)->setParam (name,
5556                 getAttribute (Ids::attr_value));
5557     Element::activate (); //finish (); // no livetime of itself, will deactivate
5558 }
5559 
5560 //-----------------------------------------------------------------------------
5561 
5562 KDE_NO_EXPORT void Visitor::visit (SMIL::Layout *n) {
5563     visit (static_cast <Element *> (n));
5564 }
5565 
5566 KDE_NO_EXPORT void Visitor::visit (SMIL::RegionBase *n) {
5567     visit (static_cast <Element *> (n));
5568 }
5569 
5570 KDE_NO_EXPORT void Visitor::visit (SMIL::Seq *n) {
5571     visit (static_cast <SMIL::GroupBase *> (n));
5572 }
5573 
5574 KDE_NO_EXPORT void Visitor::visit (SMIL::Switch *n) {
5575     visit (static_cast <SMIL::GroupBase *> (n));
5576 }
5577 
5578 KDE_NO_EXPORT void Visitor::visit (SMIL::Par *n) {
5579     visit (static_cast <SMIL::GroupBase *> (n));
5580 }
5581 
5582 KDE_NO_EXPORT void Visitor::visit (SMIL::Excl *n) {
5583     visit (static_cast <SMIL::GroupBase *> (n));
5584 }
5585 
5586 KDE_NO_EXPORT void Visitor::visit (SMIL::Transition * n) {
5587     visit (static_cast <Element *> (n));
5588 }
5589 
5590 KDE_NO_EXPORT void Visitor::visit (SMIL::AnimateBase * n) {
5591     visit (static_cast <SMIL::AnimateGroup *> (n));
5592 }
5593 
5594 KDE_NO_EXPORT void Visitor::visit (SMIL::PriorityClass * n) {
5595     visit (static_cast <Element *> (n));
5596 }
5597 
5598 KDE_NO_EXPORT void Visitor::visit (SMIL::MediaType * n) {
5599     visit (static_cast <Mrl *> (n));
5600 }
5601 
5602 KDE_NO_EXPORT void Visitor::visit (SMIL::TextMediaType * n) {
5603     visit (static_cast <SMIL::MediaType *> (n));
5604 }
5605 
5606 KDE_NO_EXPORT void Visitor::visit (SMIL::RefMediaType * n) {
5607     visit (static_cast <SMIL::MediaType *> (n));
5608 }
5609 
5610 KDE_NO_EXPORT void Visitor::visit (SMIL::Brush * n) {
5611     visit (static_cast <SMIL::MediaType *> (n));
5612 }
5613 
5614 KDE_NO_EXPORT void Visitor::visit (SMIL::SmilText *n) {
5615     visit (static_cast <Element *> (n));
5616 }
5617 
5618 KDE_NO_EXPORT void Visitor::visit (SMIL::TextFlow *n) {
5619     visit (static_cast <Element *> (n));
5620 }
5621 
5622 KDE_NO_EXPORT void Visitor::visit (SMIL::TemporalMoment *n) {
5623     visit (static_cast <Element *> (n));
5624 }
5625 
5626 KDE_NO_EXPORT void Visitor::visit (SMIL::Anchor * n) {
5627     visit (static_cast <SMIL::LinkingBase *> (n));
5628 }
5629 
5630 KDE_NO_EXPORT void Visitor::visit (SMIL::Area * n) {
5631     visit (static_cast <SMIL::LinkingBase *> (n));
5632 }