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