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 ¶, 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 ¶, 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 ¶, 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 ¶, 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 ¶m, 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 ¶, 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 ¶, 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 ¶, 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 }