1 /**
2 * Copyright (C) 2005-2007 by Koos Vriezen <koos.vriezen@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License version 2 as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Library General Public License for more details.
12 *
13 * You should have received a copy of the GNU Library General Public License
14 * along with this library; see the file COPYING.LIB. If not, write to
15 * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
16 * Boston, MA 02110-1301, USA.
17 **/
18
19 #include "config-kmplayer.h"
20
21 #include <stdlib.h>
22
23 #include <qtextstream.h>
24 #include <qcolor.h>
25 #include <qfont.h>
26 #include <qapplication.h>
27 #include <qregexp.h>
28 #include <qtimer.h>
29 #include <QBuffer>
30
31 #include <kdebug.h>
32 #include <kurl.h>
33 #include <kmimetype.h>
34 #include <kio/job.h>
35 #include <kio/jobclasses.h>
36
37 #include "kmplayer_smil.h"
38 #include "kmplayer_rp.h"
39 #include "expression.h"
40 #include "mediaobject.h"
41
42 using namespace KMPlayer;
43
44 namespace KMPlayer {
45
46 static const unsigned int begin_timer_id = (unsigned int) 3;
47 static const unsigned int dur_timer_id = (unsigned int) 4;
48 static const unsigned int anim_timer_id = (unsigned int) 5;
49 static const unsigned int trans_timer_id = (unsigned int) 6;
50 static const unsigned int trans_out_timer_id = (unsigned int) 7;
51
52 }
53
54 /* Intrinsic duration
55 * DurTime | EndTime |
56 * =======================================================================
57 * DurMedia | DurMedia | wait for event
58 * 0 | DurMedia | only wait for child elements
59 * DurMedia | 0 | intrinsic duration finished
60 */
61 //-----------------------------------------------------------------------------
62
parseTime(const QString & vl,int & dur)63 KDE_NO_EXPORT bool KMPlayer::parseTime (const QString & vl, int & dur) {
64 QByteArray ba = vl.toLatin1 ();
65 const char *cval = ba.constData ();
66 if (!cval) {
67 dur = 0;
68 return false;
69 }
70 int sign = 1;
71 bool fp_seen = false;
72 QString num;
73 const char * p = cval;
74 for ( ; *p; p++ ) {
75 if (*p == '+') {
76 if (!num.isEmpty ())
77 break;
78 else
79 sign = 1;
80 } else if (*p == '-') {
81 if (!num.isEmpty ())
82 break;
83 else
84 sign = -1;
85 } else if (*p >= '0' && *p <= '9') {
86 num += QChar (*p);
87 } else if (*p == '.') {
88 if (fp_seen)
89 break;
90 else
91 num += QChar (*p);
92 fp_seen = true;
93 } else if (*p == ' ') {
94 if (!num.isEmpty ())
95 break;
96 } else if (*p == ':') {
97 dur = Mrl::parseTimeString (vl);
98 return dur != 0;
99 } else
100 break;
101 }
102 bool ok = false;
103 double t;
104 if (!num.isEmpty ())
105 t = sign * num.toDouble (&ok);
106 if (ok) {
107 for ( ; *p; p++ ) {
108 if (*p == 'm') {
109 t *= 60;
110 break;
111 } else if (*p == 'h') {
112 t *= 60 * 60;
113 break;
114 } else if (*p != ' ')
115 break;
116 }
117 dur = (int) (100 * t);
118 } else {
119 dur = 0;
120 return false;
121 }
122 return true;
123 }
124
findRegion2(Node * p,const QString & id)125 static SMIL::Region *findRegion2 (Node *p, const QString &id) {
126 TrieString regionname_attr ("regionName");
127 for (Node *c = p->firstChild (); c; c = c->nextSibling ()) {
128 if (c->id == SMIL::id_node_region) {
129 SMIL::Region *r = static_cast <SMIL::Region *> (c);
130 QString a = r->getAttribute (regionname_attr);
131 if (a.isEmpty ())
132 a = r->getAttribute (Ids::attr_id);
133 if ((a.isEmpty () && id.isEmpty ()) || a == id)
134 return r;
135 }
136 SMIL::Region * r = findRegion2 (c, id);
137 if (r)
138 return r;
139 }
140 return 0L;
141 }
142
findRegion(Node * n,const QString & id)143 static SMIL::RegionBase *findRegion (Node *n, const QString &id) {
144 SMIL::RegionBase *region = NULL;
145 SMIL::Smil *smil = SMIL::Smil::findSmilNode (n);
146 if (smil) {
147 SMIL::Layout *layout = convertNode <SMIL::Layout> (smil->layout_node);
148 region = findRegion2 (layout, id);
149 if (!region)
150 region = convertNode <SMIL::RegionBase> (layout->root_layout);
151 }
152 return region;
153 }
154
findHeadNode(SMIL::Smil * s)155 static Node *findHeadNode (SMIL::Smil *s)
156 {
157 for (Node *h = s ? s->firstChild () : NULL; h; h = h->nextSibling ())
158 if (SMIL::id_node_head == h->id)
159 return h;
160 return NULL;
161 }
162
findTransition(Node * n,const QString & id)163 static SMIL::Transition *findTransition (Node *n, const QString &id)
164 {
165 Node *head = findHeadNode (SMIL::Smil::findSmilNode (n));
166 if (head)
167 for (Node *c = head->firstChild (); c; c = c->nextSibling())
168 if (c->id == SMIL::id_node_transition &&
169 id == static_cast <Element *> (c)->
170 getAttribute (Ids::attr_id))
171 return static_cast <SMIL::Transition *> (c);
172 return 0L;
173 }
174
parseTransitionParam(Node * n,TransitionModule & m,Runtime * r,const TrieString & para,const QString & val)175 static bool parseTransitionParam (Node *n, TransitionModule &m, Runtime *r,
176 const TrieString ¶, const QString &val) {
177 if (para == "transIn") {
178 SMIL::Transition *t = findTransition (n, val);
179 if (t) {
180 m.trans_in = t;
181 r->trans_in_dur = t->dur;
182 } else {
183 kWarning() << "Transition " << val << " not found in head";
184 }
185 } else if (para == "transOut") {
186 m.trans_out = findTransition (n, val);
187 if (!m.trans_out)
188 kWarning() << "Transition " << val << " not found in head";
189 } else {
190 return false;
191 }
192 return true;
193 }
194
findLocalNodeById(Node * n,const QString & id)195 static Node *findLocalNodeById (Node *n, const QString & id) {
196 SMIL::Smil *s = SMIL::Smil::findSmilNode (n);
197 if (s)
198 return s->document ()->getElementById (s, id, false);
199 return 0L;
200 }
201
parseFit(const char * cval)202 static Fit parseFit (const char *cval) {
203 Fit fit;
204 if (!cval)
205 fit = fit_hidden;
206 else if (!strcmp (cval, "fill"))
207 fit = fit_fill;
208 else if (!strcmp (cval, "hidden"))
209 fit = fit_hidden;
210 else if (!strcmp (cval, "meet"))
211 fit = fit_meet;
212 else if (!strcmp (cval, "scroll"))
213 fit = fit_scroll;
214 else if (!strcmp (cval, "slice"))
215 fit = fit_slice;
216 else
217 fit = fit_default;
218 return fit;
219 }
220
221 //-----------------------------------------------------------------------------
222
PostponedEvent(bool postponed)223 PostponedEvent::PostponedEvent (bool postponed)
224 : is_postponed (postponed) {}
225
226 //-----------------------------------------------------------------------------
227
DurationItem()228 Runtime::DurationItem::DurationItem ()
229 : durval (DurTimer), offset (0), next (NULL) {}
230
231 Runtime::DurationItem &
operator =(const Runtime::DurationItem & d)232 Runtime::DurationItem::operator = (const Runtime::DurationItem &d) {
233 durval = d.durval;
234 offset = d.offset;
235 payload = d.payload;
236 connection.assign (&d.connection);
237 return *this;
238 }
239
matches(const Duration dur,const Posting * post)240 bool Runtime::DurationItem::matches (const Duration dur, const Posting *post) {
241 return dur == durval &&
242 connection.signaler () == post->source.ptr () &&
243 ((Duration) MsgStateChanged != durval || post->payload == payload);
244 }
245
clear()246 void Runtime::DurationItem::clear() {
247 durval = DurTimer;
248 offset = 0;
249 payload = NULL;
250 connection.disconnect ();
251 if (next) {
252 next->clear ();
253 delete next;
254 next = NULL;
255 }
256 }
257
getDefaultFill(NodePtr n)258 static Runtime::Fill getDefaultFill (NodePtr n) {
259 for (NodePtr p = n->parentNode (); p; p = p->parentNode ()) {
260 Runtime *rt = static_cast <Runtime *> (p->role (RoleTiming));
261 if (rt) {
262 if (rt->fill_def != Runtime::fill_inherit)
263 return rt->fill_def;
264 else if (rt->fill == Runtime::fill_default)
265 return rt->fill_active;//assume parent figured out this
266 } else if (p->id == SMIL::id_node_smil)
267 break;
268 }
269 return Runtime::fill_auto;
270 }
271
Runtime(Element * e)272 KDE_NO_CDTOR_EXPORT Runtime::Runtime (Element *e)
273 : begin_timer (NULL),
274 duration_timer (NULL),
275 started_timer (NULL),
276 stopped_timer (NULL),
277 fill_active (fill_auto),
278 element (NULL) {
279 init();
280 element = e;
281 }
282
283
~Runtime()284 KDE_NO_CDTOR_EXPORT Runtime::~Runtime () {
285 if (begin_timer)
286 element->document ()->cancelPosting (begin_timer);
287 if (duration_timer)
288 element->document ()->cancelPosting (duration_timer);
289 element = NULL;
290 init ();
291 }
292
init()293 KDE_NO_EXPORT void Runtime::init ()
294 {
295 if (element && begin_timer) {
296 element->document ()->cancelPosting (begin_timer);
297 begin_timer = NULL;
298 }
299 if (element && duration_timer) {
300 element->document ()->cancelPosting (duration_timer);
301 duration_timer = NULL;
302 }
303 repeat = repeat_count = 1;
304 trans_in_dur = 0;
305 timingstate = TimingsInit;
306 for (int i = 0; i < (int) DurTimeLast; i++)
307 durations [i].clear ();
308 endTime ().durval = DurMedia;
309 start_time = finish_time = 0;
310 fill = fill_default;
311 fill_def = fill_inherit;
312 }
313
initialize()314 KDE_NO_EXPORT void Runtime::initialize ()
315 {
316 if (fill == fill_default) {
317 if (fill_def == fill_inherit)
318 fill_active = getDefaultFill (element);
319 else
320 fill_active = fill_def;
321 }
322 timingstate = Runtime::TimingsInitialized;
323 }
324
325 static
setDurationItem(Node * n,const QString & val,Runtime::DurationItem * itm)326 void setDurationItem (Node *n, const QString &val, Runtime::DurationItem *itm) {
327 int dur = -2; // also 0 for 'media' duration, so it will not update then
328 QString vs = val.trimmed ();
329 QString vl = vs.toLower ();
330 QByteArray ba = vl.toLatin1 ();
331 const char *cval = ba.constData ();
332 int offset = 0;
333 VirtualVoid *payload = NULL;
334 if (cval && cval[0]) {
335 QString idref;
336 const char * p = cval;
337 if (parseTime (vl, offset)) {
338 dur = Runtime::DurTimer;
339 } else if (!strncmp (cval, "id(", 3)) {
340 p = strchr (cval + 3, ')');
341 if (p) {
342 idref = vs.mid (3, p - cval - 3);
343 p++;
344 }
345 if (*p) {
346 const char *q = strchr (p, '(');
347 if (q)
348 p = q;
349 }
350 } else if (!strncmp (cval, "indefinite", 10)) {
351 offset = -1;
352 dur = Runtime::DurIndefinite;
353 } else if (!strncmp (cval, "media", 5)) {
354 dur = Runtime::DurMedia;
355 }
356 if (dur == -2) {
357 NodePtr target;
358 const char * q = p;
359 if (idref.isEmpty ()) {
360 bool last_esc = false;
361 for ( ; *q; q++) {
362 if (*q == '\\') {
363 if (last_esc) {
364 idref += QChar ('\\');
365 last_esc = false;
366 } else
367 last_esc = true;
368 } else if (*q == '.' && !last_esc) {
369 break;
370 } else
371 idref += QChar (*q);
372 }
373 if (!*q)
374 idref = vs.mid (p - cval);
375 else
376 idref = vs.mid (p - cval, q - p);
377 }
378 if (*q) {
379 ++q;
380 if (!idref.isEmpty ()) {
381 target = findLocalNodeById (n, idref);
382 if (!target)
383 q = p;
384 }
385 } else {
386 q = p;
387 }
388 if (parseTime (vl.mid (q-cval), offset)) {
389 dur = Runtime::DurStart;
390 } else if (*q && !strncmp (q, "end", 3)) {
391 dur = Runtime::DurEnd;
392 parseTime (vl.mid (q + 3 - cval), offset);
393 } else if (*q && !strncmp (q, "begin", 5)) {
394 dur = Runtime::DurStart;
395 parseTime (vl.mid (q + 5 - cval), offset);
396 } else if (*q && !strncmp (q, "activateevent", 13)) {
397 dur = Runtime::DurActivated;
398 parseTime (vl.mid (q + 13 - cval), offset);
399 } else if (*q && !strncmp (q, "inboundsevent", 13)) {
400 dur = Runtime::DurInBounds;
401 parseTime (vl.mid (q + 13 - cval), offset);
402 } else if (*q && !strncmp (q, "outofboundsevent", 16)) {
403 dur = Runtime::DurOutBounds;
404 parseTime (vl.mid (q + 16 - cval), offset);
405 } else if (*q && !strncmp (q, "statechange", 11)) {
406 int op = vl.indexOf ('(', 11);
407 if (op > -1) {
408 int cp = vl.indexOf (')', op + 1);
409 if (cp > -1) {
410 payload = evaluateExpr(vl.mid(op + 1, cp - op - 1).toUtf8(), "data");
411 dur = Runtime::DurStateChanged;
412 }
413 }
414 } else if (*q && !strncmp (q, "accesskey", 9)) {
415 int op = vl.indexOf ('(', 9);
416 if (op > -1) {
417 int cp = vl.indexOf (')', op + 1);
418 if (cp > -1) {
419 QString ch = vl.mid (op + 1, cp - op - 1);
420 if (!ch.isEmpty ()) {
421 payload = new KeyLoad (ch[0].unicode ());
422 dur = Runtime::DurAccessKey;
423 target = n->document ();
424 }
425 }
426 }
427 } else
428 kWarning () << "setDuration no match " << cval;
429 if (!target &&
430 dur >= Runtime::DurActivated && dur <= Runtime::DurOutBounds)
431 target = n;
432 if (target && dur != Runtime::DurTimer)
433 itm->connection.connect (target, (MessageType)dur, n, payload);
434 }
435 }
436 itm->durval = (Runtime::Duration) dur;
437 itm->offset = offset;
438 itm->payload = payload;
439 }
440
441 static
setDurationItems(Node * n,const QString & s,Runtime::DurationItem * item)442 void setDurationItems (Node *n, const QString &s, Runtime::DurationItem *item) {
443 item->clear ();
444 Runtime::DurationItem *last = item;
445 QStringList list = s.split (QChar (';'));
446 bool timer_set = false;
447 for (int i = 0; i < list.count(); ++i) {
448 QString val = list[i].trimmed();
449 if (!val.isEmpty ()) {
450 Runtime::DurationItem di;
451 setDurationItem (n, val, &di);
452 switch (di.durval) {
453 case Runtime::DurTimer:
454 case Runtime::DurIndefinite:
455 case Runtime::DurMedia:
456 *item = di;
457 timer_set = true;
458 break;
459 default:
460 last = last->next = new Runtime::DurationItem;
461 *last = di;
462 }
463 }
464 }
465 if (item->next && !timer_set)
466 item->durval = Runtime::DurIndefinite;
467 }
468
disabledByExpr(Runtime * rt)469 static bool disabledByExpr (Runtime *rt) {
470 bool b = false;
471 if (!rt->expr.isEmpty ()) {
472 Expression* res = evaluateExpr(rt->expr.toUtf8(), "data");
473 if (res) {
474 SMIL::Smil *smil = SMIL::Smil::findSmilNode (rt->element);
475 res->setRoot (smil ? smil->state_node.ptr() : NULL);
476 b = !res->toBool ();
477 delete res;
478 }
479 }
480 return b;
481 }
482
483 /**
484 * start, or restart in case of re-use, the durations
485 */
start()486 KDE_NO_EXPORT void Runtime::start () {
487 if (begin_timer || duration_timer)
488 element->init ();
489 timingstate = timings_began;
490
491 int offset = 0;
492 bool stop = true;
493 for (DurationItem *dur = durations + (int)BeginTime; dur; dur = dur->next)
494 switch (dur->durval) {
495 case DurStart: { // check started/finished
496 Node *sender = dur->connection.signaler ();
497 if (sender && sender->state >= Node::state_began) {
498 offset = dur->offset;
499 Runtime *rt = (Runtime*)sender->role (RoleTiming);
500 if (rt)
501 offset -= element->document()->last_event_time/10 - rt->start_time;
502 stop = false;
503 kWarning() << "start trigger on started element";
504 } // else wait for start event
505 break;
506 }
507 case DurEnd: { // check finished
508 Node *sender = dur->connection.signaler ();
509 if (sender && sender->state >= Node::state_finished) {
510 int offset = dur->offset;
511 Runtime *rt = (Runtime*)sender->role (RoleTiming);
512 if (rt)
513 offset -= element->document()->last_event_time/10 - rt->finish_time;
514 stop = false;
515 kWarning() << "start trigger on finished element";
516 } // else wait for end event
517 break;
518 }
519 case DurTimer:
520 offset = dur->offset;
521 stop = false;
522 break;
523 default:
524 break;
525 }
526 if (stop) // wait for event
527 tryFinish ();
528 else if (offset > 0) // start timer
529 begin_timer = element->document ()->post (element,
530 new TimerPosting (10 * offset, begin_timer_id));
531 else // start now
532 propagateStart ();
533 }
534
finish()535 KDE_NO_EXPORT void Runtime::finish () {
536 if (started () || timingstate == timings_began) {
537 doFinish (); // reschedule through Runtime::stopped
538 } else {
539 finish_time = element->document ()->last_event_time/10;
540 repeat_count = repeat;
541 NodePtrW guard = element;
542 element->Node::finish ();
543 if (guard && element->document ()->active ()) { // check for reset
544 Posting event (element, MsgEventStopped);
545 element->deliver (MsgEventStopped, &event);
546 }
547 }
548 }
549
startAndBeginNode()550 KDE_NO_EXPORT void Runtime::startAndBeginNode () {
551 if (begin_timer || duration_timer)
552 element->init ();
553 timingstate = timings_began;
554 propagateStart ();
555 }
556
557 KDE_NO_EXPORT
parseParam(const TrieString & name,const QString & val)558 bool Runtime::parseParam (const TrieString & name, const QString & val) {
559 if (name == Ids::attr_begin) {
560 setDurationItems (element, val, durations + (int) BeginTime);
561 if ((timingstate == timings_began && !begin_timer) ||
562 timingstate >= timings_stopped) {
563 if (beginTime ().offset > 0) { // create a timer for start
564 if (begin_timer) {
565 element->document ()->cancelPosting (begin_timer);
566 begin_timer = NULL;
567 }
568 if (beginTime ().durval == DurTimer)
569 begin_timer = element->document ()->post (element,
570 new TimerPosting (10 * beginTime ().offset, begin_timer_id));
571 } else { // start now
572 propagateStart ();
573 }
574 }
575 } else if (name == Ids::attr_dur) {
576 setDurationItems (element, val, durations + (int) DurTime);
577 } else if (name == Ids::attr_end) {
578 setDurationItems (element, val, durations + (int) EndTime);
579 } else if (name.startsWith (Ids::attr_fill)) {
580 Fill * f = &fill;
581 if (name != Ids::attr_fill) {
582 f = &fill_def;
583 *f = fill_inherit;
584 } else
585 *f = fill_default;
586 fill_active = fill_auto;
587 if (val == "freeze")
588 *f = fill_freeze;
589 else if (val == "hold")
590 *f = fill_hold;
591 else if (val == "auto")
592 *f = fill_auto;
593 else if (val == "remove")
594 *f = fill_remove;
595 else if (val == "transition")
596 *f = fill_transition;
597 if (fill == fill_default) {
598 if (fill_def == fill_inherit)
599 fill_active = getDefaultFill (element);
600 else
601 fill_active = fill_def;
602 } else
603 fill_active = fill;
604 } else if (name == Ids::attr_title) {
605 Mrl *mrl = element->mrl ();
606 if (mrl)
607 mrl->title = val;
608 } else if (name == "endsync") {
609 if ((durTime ().durval == DurMedia || durTime ().durval == 0) &&
610 endTime ().durval == DurMedia) {
611 Node *e = findLocalNodeById (element, val);
612 if (e) {
613 durations [(int) EndTime].connection.connect (
614 e, MsgEventStopped, element);
615 durations [(int) EndTime].durval = (Duration) MsgEventStopped;
616 }
617 }
618 } else if (name.startsWith ("repeat")) {
619 if (val.indexOf ("indefinite") > -1)
620 repeat = repeat_count = DurIndefinite;
621 else
622 repeat = repeat_count = val.toInt ();
623 } else if (name.startsWith ("expr")) {
624 expr = val;
625 } else // TODO restart/restartDefault
626 return false;
627 return true;
628 }
629
message(MessageType msg,void * content)630 KDE_NO_EXPORT void Runtime::message (MessageType msg, void *content) {
631 switch (msg) {
632 case MsgEventTimer: {
633 TimerPosting *te = static_cast <TimerPosting *> (content);
634 if (te->event_id == begin_timer_id) {
635 begin_timer = NULL;
636 propagateStart ();
637 } else if (te->event_id == dur_timer_id) {
638 duration_timer = NULL;
639 doFinish ();
640 } else {
641 kWarning () << "unhandled timer event";
642 }
643 return;
644 }
645 case MsgEventStarted: {
646 Posting *event = static_cast <Posting *> (content);
647 if (event->source.ptr () == element) {
648 started_timer = NULL;
649 start_time = element->document ()->last_event_time/10;
650 setDuration ();
651 NodePtrW guard = element;
652 element->deliver (MsgEventStarted, event);
653 if (guard) {
654 element->begin ();
655 if (!element->document ()->postponed ())
656 tryFinish ();
657 }
658 return;
659 }
660 break;
661 }
662 case MsgEventStopped: {
663 Posting *event = static_cast <Posting *> (content);
664 if (event->source.ptr () == element) {
665 stopped_timer = NULL;
666 stopped ();
667 return;
668 }
669 break;
670 }
671 default:
672 break;
673 }
674 if ((int) msg >= (int) DurLastDuration)
675 return;
676
677 Posting *event = static_cast <Posting *> (content);
678 for (DurationItem *dur = beginTime ().next; dur; dur = dur->next) {
679 if (dur->matches ((Duration) msg, event)) {
680 if (started ())
681 element->message (MsgStateRewind);
682 else
683 element->activate ();
684 if (element && dur->offset > 0) {
685 if (begin_timer)
686 element->document ()->cancelPosting (begin_timer);
687 begin_timer = element->document ()->post (element,
688 new TimerPosting(10 * dur->offset, begin_timer_id));
689 } else { //FIXME neg. offsets
690 propagateStart ();
691 }
692 if (element->state == Node::state_finished)
693 element->state = Node::state_activated;//rewind to activated
694 return;
695 }
696 }
697 if (started ()) {
698 Posting *event = static_cast <Posting *> (content);
699 for (DurationItem *dur = endTime ().next; dur; dur = dur->next)
700 if (dur->matches ((Duration) msg, event)) {
701 if (element && dur->offset > 0) {
702 if (duration_timer)
703 element->document ()->cancelPosting (duration_timer);
704 duration_timer = element->document ()->post (element,
705 new TimerPosting (10 * dur->offset, dur_timer_id));
706 } else {
707 doFinish ();
708 }
709 break;
710 }
711 }
712 }
713
role(RoleType msg,void * content)714 KDE_NO_EXPORT void *Runtime::role (RoleType msg, void *content) {
715 switch (msg) {
716 case RoleReceivers: {
717 switch ((MessageType) (long) content) {
718 case MsgEventStopped:
719 return &m_StoppedListeners;
720 case MsgEventStarted:
721 return &m_StartedListeners;
722 case MsgEventStarting:
723 return &m_StartListeners;
724 case MsgChildTransformedIn:
725 break;
726 default:
727 kWarning () << "unknown event requested " << (int)msg;
728 }
729 return NULL;
730 }
731 default:
732 break;
733 }
734 return MsgUnhandled;
735 }
736
propagateStop(bool forced)737 KDE_NO_EXPORT void Runtime::propagateStop (bool forced) {
738 if (state() == TimingsInit || state() >= timings_stopped)
739 return; // nothing to stop
740 if (!forced) {
741 if ((durTime ().durval == DurMedia ||
742 durTime ().durval == DurTransition ) &&
743 endTime ().durval == DurMedia)
744 return; // wait for external eof
745 if (endTime ().durval != DurTimer && endTime ().durval != DurMedia &&
746 (started () || beginTime().durval == DurTimer))
747 return; // wait for event
748 if (durTime ().durval == DurIndefinite)
749 return; // this may take a while :-)
750 if (duration_timer)
751 return; // timerEvent will call us with forced=true
752 // bail out if a child still running
753 for (Node *c = element->firstChild (); c; c = c->nextSibling ())
754 if (c->unfinished () || Node::state_deferred == c->state)
755 return; // a child still running
756 }
757 bool was_started (started ());
758 timingstate = timings_freezed;
759 if (begin_timer) {
760 element->document ()->cancelPosting (begin_timer);
761 begin_timer = NULL;
762 }
763 if (duration_timer) {
764 element->document ()->cancelPosting (duration_timer);
765 duration_timer = NULL;
766 }
767 if (was_started && element->document ()->active ())
768 stopped_timer = element->document()->post (
769 element, new Posting (element, MsgEventStopped));
770 else if (element->unfinished ())
771 element->finish ();
772 }
773
propagateStart()774 KDE_NO_EXPORT void Runtime::propagateStart () {
775 if (begin_timer) {
776 element->document ()->cancelPosting (begin_timer);
777 begin_timer = NULL;
778 }
779 if (disabledByExpr (this)) {
780 if (timings_freezed == timingstate)
781 element->message (MsgStateFreeze);
782 timingstate = TimingsDisabled;
783 return;
784 }
785 timingstate = trans_in_dur ? TimingsTransIn : timings_started;
786 element->deliver (MsgEventStarting, element);
787 started_timer = element->document()->post (
788 element, new Posting (element, MsgEventStarted));
789 }
790
791 /**
792 * begin_timer timer expired
793 */
setDuration()794 KDE_NO_EXPORT void Runtime::setDuration () {
795 if (begin_timer) {
796 element->document ()->cancelPosting (begin_timer);
797 begin_timer = NULL;
798 }
799 if (duration_timer) {
800 element->document ()->cancelPosting (duration_timer);
801 duration_timer = NULL;
802 }
803 int duration = 0;
804 if (durTime ().durval == DurTimer) {
805 duration = durTime ().offset;
806 if (endTime ().durval == DurTimer &&
807 (!duration || endTime().offset - beginTime().offset < duration))
808 duration = endTime ().offset - beginTime ().offset;
809 } else if (endTime ().durval == DurTimer) {
810 duration = endTime ().offset;
811 }
812 if (duration > 0)
813 duration_timer = element->document ()->post (element,
814 new TimerPosting (10 * duration, dur_timer_id));
815 }
816
started() const817 bool Runtime::started () const {
818 return timingstate >= timings_started && timingstate < timings_stopped;
819 }
820
runtimeBegan(Runtime * r)821 static bool runtimeBegan (Runtime *r) {
822 return r->timingstate >= Runtime::timings_began &&
823 r->timingstate < Runtime::timings_stopped;
824 }
825
826 /**
827 * duration_timer timer expired or no duration set after started
828 */
stopped()829 KDE_NO_EXPORT void Runtime::stopped () {
830 if (element->active ()) {
831 if (repeat_count == DurIndefinite || 0 < --repeat_count) {
832 element->message (MsgStateRewind);
833 beginTime ().offset = 0;
834 beginTime ().durval = DurTimer;
835 if (begin_timer)
836 element->document ()->cancelPosting (begin_timer);
837 propagateStart ();
838 } else {
839 repeat_count = repeat;
840 element->finish ();
841 }
842 }
843 }
844
845 //-----------------------------------------------------------------------------
846
SizeType()847 KDE_NO_CDTOR_EXPORT SizeType::SizeType () {
848 reset ();
849 }
850
SizeType(const QString & s,bool perc)851 KDE_NO_CDTOR_EXPORT SizeType::SizeType (const QString & s, bool perc)
852 : perc_size (perc ? -100 : 0) {
853 *this = s;
854 }
855
reset()856 void SizeType::reset () {
857 perc_size = 0;
858 abs_size = 0;
859 isset = false;
860 has_percentage = false;
861 }
862
operator =(const QString & s)863 SizeType & SizeType::operator = (const QString & s) {
864 QString strval (s);
865 int p = strval.indexOf (QChar ('%'));
866 if (p > -1) {
867 strval.truncate (p);
868 has_percentage = true;
869 }
870 int px = strval.indexOf (QChar ('p')); // strip px
871 if (px > -1)
872 strval.truncate (px);
873 double d = strval.toDouble (&isset);
874 if (isset) {
875 if (p > -1)
876 perc_size = d;
877 else if (perc_size < 0)
878 perc_size = 100 * d;
879 else
880 abs_size = d;
881 }
882 return *this;
883 }
884
operator =(Single d)885 SizeType & SizeType::operator = (Single d) {
886 reset ();
887 abs_size = d;
888 return *this;
889 }
890
operator +=(const SizeType & s)891 SizeType & SizeType::operator += (const SizeType & s) {
892 perc_size += s.perc_size;
893 abs_size += s.abs_size;
894 return *this;
895 }
896
operator -=(const SizeType & s)897 SizeType & SizeType::operator -= (const SizeType & s) {
898 perc_size -= s.perc_size;
899 abs_size -= s.abs_size;
900 return *this;
901 }
902
size(Single relative_to) const903 Single SizeType::size (Single relative_to) const {
904 Single s = abs_size;
905 s += perc_size * relative_to / 100;
906 return s;
907 }
908
toString() const909 QString SizeType::toString () const {
910 if (isset) {
911 if (has_percentage)
912 return QString ("%1%").arg ((int) size (100));
913 return QString::number ((double) size (100));
914 }
915 return QString ();
916 }
917
918 //-----------------%<----------------------------------------------------------
919
920 template<>
intersect(const IRect & r) const921 IRect IRect::intersect (const IRect & r) const {
922 int a (point.x < r.point.x ? r.point.x : point.x);
923 int b (point.y < r.point.y ? r.point.y : point.y);
924 return IRect (a, b,
925 ((point.x + size.width < r.point.x + r.size.width)
926 ? point.x + size.width : r.point.x + r.size.width) - a,
927 ((point.y + size.height < r.point.y + r.size.height)
928 ? point.y + size.height : r.point.y + r.size.height) - b);
929 }
930
931 //-----------------------------------------------------------------------------
932
resetSizes()933 KDE_NO_EXPORT void CalculatedSizer::resetSizes () {
934 left.reset ();
935 top.reset ();
936 width.reset ();
937 height.reset ();
938 right.reset ();
939 bottom.reset ();
940 reg_point.truncate (0);
941 reg_align = QString::fromLatin1 ("topLeft");
942 }
943
regPoints(const QString & str,Single & x,Single & y)944 static bool regPoints (const QString & str, Single & x, Single & y) {
945 QByteArray ba = str.toLower ().toLatin1 ();
946 const char *rp = ba.constData ();
947 if (!rp)
948 return false;
949 if (!strcmp (rp, "center")) {
950 x = 50;
951 y = 50;
952 } else {
953 if (!strncmp (rp, "top", 3)) {
954 y = 0;
955 rp += 3;
956 } else if (!strncmp (rp, "mid", 3)) {
957 y = 50;
958 rp += 3;
959 } else if (!strncmp (rp, "bottom", 6)) {
960 y = 100;
961 rp += 6;
962 } else
963 return false;
964 if (!strcmp (rp, "left")) {
965 x = 0;
966 } else if (!strcmp (rp, "mid")) {
967 x = 50;
968 } else if (!strcmp (rp, "right")) {
969 x = 100;
970 } else
971 return false;
972 }
973 return true;
974 }
975
976 KDE_NO_EXPORT
applyRegPoints(Node * node,CalculatedSizer * region_sizes,Single w,Single h,Single & xoff,Single & yoff,Single & w1,Single & h1)977 bool CalculatedSizer::applyRegPoints (Node * node,
978 CalculatedSizer *region_sizes, Single w, Single h,
979 Single & xoff, Single & yoff, Single & w1, Single & h1) {
980 QString rp = reg_point;
981 if (rp.isEmpty () && region_sizes)
982 rp = region_sizes->reg_point;
983 if (rp.isEmpty ())
984 return false;
985 Single rpx, rpy, rax, ray;
986 if (!regPoints (rp, rpx, rpy)) {
987 node = SMIL::Smil::findSmilNode (node);
988 if (!node)
989 return false;
990 node = static_cast <SMIL::Smil *> (node)->layout_node.ptr ();
991 if (!node)
992 return false;
993 Node *c = node->firstChild ();
994 for (; c; c = c->nextSibling ())
995 if (c->id == SMIL::id_node_regpoint &&
996 static_cast<Element*>(c)->getAttribute (Ids::attr_id)
997 == rp) {
998 Single i1, i2; // dummies
999 SMIL::RegPoint *rp_elm = static_cast <SMIL::RegPoint *> (c);
1000 rp_elm->sizes.calcSizes (0L, NULL, 100, 100, rpx, rpy, i1, i2);
1001 QString ra = rp_elm->getAttribute ("regAlign");
1002 if (!ra.isEmpty () && reg_align.isEmpty ())
1003 reg_align = ra;
1004 break;
1005 }
1006 if (!c)
1007 return false; // not found
1008 }
1009 QString ra = reg_align;
1010 if (ra.isEmpty () && region_sizes)
1011 ra = region_sizes->reg_align;
1012 if (!regPoints (ra, rax, ray))
1013 rax = ray = 0; // default back to topLeft
1014 if (!(int)w1 || !(int)h1) {
1015 xoff = w * (rpx - rax) / 100;
1016 yoff = h * (rpy - ray) / 100;
1017 w1 = w - w * (rpx > rax ? (rpx - rax) : (rax - rpx)) / 100;
1018 h1 = h - h * (rpy > ray ? (rpy - ray) : (ray - rpy)) / 100;
1019 } else {
1020 xoff = (w * rpx - w1 * rax) / 100;
1021 yoff = (h * rpy - h1 * ray) / 100;
1022 }
1023 return true; // success getting sizes based on regPoint
1024 }
1025
calcSizes(Node * node,CalculatedSizer * region_sz,Single w,Single h,Single & xoff,Single & yoff,Single & w1,Single & h1)1026 KDE_NO_EXPORT void CalculatedSizer::calcSizes (Node * node,
1027 CalculatedSizer *region_sz, Single w, Single h,
1028 Single & xoff, Single & yoff, Single & w1, Single & h1) {
1029 if (region_sz && applyRegPoints (node, region_sz, w, h, xoff, yoff, w1, h1))
1030 return;
1031 if (left.isSet ())
1032 xoff = left.size (w);
1033 else if (width.isSet ()) {
1034 if (right.isSet ())
1035 xoff = w - width.size (w) - right.size (w);
1036 else
1037 xoff = 0;
1038 } else
1039 xoff = 0;
1040 if (top.isSet ())
1041 yoff = top.size (h);
1042 else if (height.isSet ()) {
1043 if (bottom.isSet ())
1044 yoff = h - height.size (h) - bottom.size (h);
1045 else
1046 yoff = 0;
1047 } else
1048 yoff = 0;
1049 if (width.isSet ())
1050 w1 = width.size (w);
1051 else if (right.isSet ())
1052 w1 = w - xoff - right.size (w);
1053 else
1054 w1 = w - xoff;
1055 if (w1 < 0)
1056 w1 = 0;
1057 if (height.isSet ())
1058 h1 = height.size (h);
1059 else if (bottom.isSet ())
1060 h1 = h - yoff - bottom.size (h);
1061 else
1062 h1 = h - yoff;
1063 if (h1 < 0)
1064 h1 = 0;
1065 }
1066
1067 KDE_NO_EXPORT
setSizeParam(const TrieString & name,const QString & val)1068 bool CalculatedSizer::setSizeParam(const TrieString &name, const QString &val) {
1069 if (name == Ids::attr_left) {
1070 left = val;
1071 } else if (name == Ids::attr_top) {
1072 top = val;
1073 } else if (name == Ids::attr_width) {
1074 width = val;
1075 } else if (name == Ids::attr_height) {
1076 height = val;
1077 } else if (name == Ids::attr_right) {
1078 right = val;
1079 } else if (name == Ids::attr_bottom) {
1080 bottom = val;
1081 } else if (name == "regPoint") {
1082 reg_point = val;
1083 } else if (name == "regAlign") {
1084 reg_align = val;
1085 } else if (name == "mediaAlign") {
1086 reg_point = val;
1087 reg_align = val;
1088 } else
1089 return false;
1090 return true;
1091 }
1092
1093 KDE_NO_EXPORT void
move(const SizeType & x,const SizeType & y)1094 CalculatedSizer::move (const SizeType &x, const SizeType &y) {
1095 if (left.isSet ()) {
1096 if (right.isSet ()) {
1097 right += x;
1098 right -= left;
1099 }
1100 left = x;
1101 } else if (right.isSet ()) {
1102 right = x;
1103 } else {
1104 left = x;
1105 }
1106 if (top.isSet ()) {
1107 if (bottom.isSet ()) {
1108 bottom += y;
1109 bottom -= top;
1110 }
1111 top = y;
1112 } else if (bottom.isSet ()) {
1113 bottom = y;
1114 } else {
1115 top = y;
1116 }
1117 }
1118
1119 //-----------------------------------------------------------------------------
1120
MouseListeners()1121 KDE_NO_CDTOR_EXPORT MouseListeners::MouseListeners () {}
1122
receivers(MessageType eid)1123 ConnectionList *MouseListeners::receivers (MessageType eid) {
1124 switch (eid) {
1125 case MsgEventClicked:
1126 return &m_ActionListeners;
1127 case MsgEventPointerInBounds:
1128 return &m_InBoundsListeners;
1129 case MsgEventPointerOutBounds:
1130 return &m_OutOfBoundsListeners;
1131 default:
1132 break;
1133 }
1134 return NULL;
1135 }
1136
1137 //-----------------------------------------------------------------------------
1138
fromScheduleGroup(NodePtr & d,const QString & tag)1139 static Element * fromScheduleGroup (NodePtr & d, const QString & tag) {
1140 QByteArray ba = tag.toLatin1 ();
1141 const char *ctag = ba.constData ();
1142 if (!strcmp (ctag, "par"))
1143 return new SMIL::Par (d);
1144 else if (!strcmp (ctag, "seq"))
1145 return new SMIL::Seq (d);
1146 else if (!strcmp (ctag, "excl"))
1147 return new SMIL::Excl (d);
1148 return NULL;
1149 }
1150
fromParamGroup(NodePtr & d,const QString & tag)1151 static Element * fromParamGroup (NodePtr & d, const QString & tag) {
1152 QByteArray ba = tag.toLatin1 ();
1153 const char *ctag = ba.constData ();
1154 if (!strcmp (ctag, "param"))
1155 return new SMIL::Param (d);
1156 else if (!strcmp (ctag, "area") || !strcmp (ctag, "anchor"))
1157 return new SMIL::Area (d, tag);
1158 return NULL;
1159 }
1160
fromAnimateGroup(NodePtr & d,const QString & tag)1161 static Element * fromAnimateGroup (NodePtr & d, const QString & tag) {
1162 QByteArray ba = tag.toLatin1 ();
1163 const char *ctag = ba.constData ();
1164 if (!strcmp (ctag, "set"))
1165 return new SMIL::Set (d);
1166 else if (!strcmp (ctag, "animate"))
1167 return new SMIL::Animate (d);
1168 else if (!strcmp (ctag, "animateColor"))
1169 return new SMIL::AnimateColor (d);
1170 else if (!strcmp (ctag, "animateMotion"))
1171 return new SMIL::AnimateMotion (d);
1172 else if (!strcmp (ctag, "newvalue"))
1173 return new SMIL::NewValue (d);
1174 else if (!strcmp (ctag, "setvalue"))
1175 return new SMIL::SetValue (d);
1176 else if (!strcmp (ctag, "delvalue"))
1177 return new SMIL::DelValue (d);
1178 else if (!strcmp (ctag, "send"))
1179 return new SMIL::Send (d);
1180 return NULL;
1181 }
1182
fromMediaContentGroup(NodePtr & d,const QString & tag)1183 static Element * fromMediaContentGroup (NodePtr & d, const QString & tag) {
1184 QByteArray ba = tag.toLatin1 ();
1185 const char *taglatin = ba.constData ();
1186 if (!strcmp (taglatin, "video") ||
1187 !strcmp (taglatin, "audio") ||
1188 !strcmp (taglatin, "img") ||
1189 !strcmp (taglatin, "animation") ||
1190 !strcmp (taglatin, "textstream") ||
1191 !strcmp (taglatin, "ref"))
1192 return new SMIL::RefMediaType (d, ba);
1193 else if (!strcmp (taglatin, "text"))
1194 return new SMIL::TextMediaType (d);
1195 else if (!strcmp (taglatin, "brush"))
1196 return new SMIL::Brush (d);
1197 else if (!strcmp (taglatin, "a"))
1198 return new SMIL::Anchor (d);
1199 else if (!strcmp (taglatin, "smilText"))
1200 return new SMIL::SmilText (d);
1201 // animation, textstream
1202 return NULL;
1203 }
1204
fromContentControlGroup(NodePtr & d,const QString & tag)1205 static Element * fromContentControlGroup (NodePtr & d, const QString & tag) {
1206 if (!strcmp (tag.toLatin1 ().constData (), "switch"))
1207 return new SMIL::Switch (d);
1208 return NULL;
1209 }
1210
fromTextFlowGroup(NodePtr & d,const QString & tag)1211 static Element *fromTextFlowGroup (NodePtr &d, const QString &tag) {
1212 QByteArray ba = tag.toLatin1 ();
1213 const char *taglatin = ba.constData ();
1214 if (!strcmp (taglatin, "div"))
1215 return new SMIL::TextFlow (d, SMIL::id_node_div, tag.toUtf8 ());
1216 if (!strcmp (taglatin, "span"))
1217 return new SMIL::TextFlow (d, SMIL::id_node_span, tag.toUtf8 ());
1218 if (!strcmp (taglatin, "p"))
1219 return new SMIL::TextFlow (d, SMIL::id_node_p, tag.toUtf8 ());
1220 if (!strcmp (taglatin, "br"))
1221 return new SMIL::TextFlow (d, SMIL::id_node_br, tag.toUtf8 ());
1222 return NULL;
1223 }
1224
setRGBA(unsigned int color,int opacity)1225 static unsigned int setRGBA (unsigned int color, int opacity) {
1226 int a = ((color >> 24) & 0xff) * opacity / 100;
1227 return (a << 24) | (color & 0xffffff);
1228 }
1229
init()1230 void SmilColorProperty::init ()
1231 {
1232 color = 0;
1233 opacity = 100;
1234 }
1235
rgbFromValue(const QString & val)1236 static unsigned int rgbFromValue (const QString& val) {
1237 SmilColorProperty p;
1238 p.init();
1239 p.setColor (val);
1240 return 0xffffff & p.color;
1241 }
1242
setColor(const QString & val)1243 void SmilColorProperty::setColor (const QString &val)
1244 {
1245 if (val.isEmpty () || val == "transparent")
1246 color = 0;
1247 else if (val.startsWith (QChar ('#')) && val.length() == 9)
1248 color = val.mid (1).toUInt (NULL, 16);
1249 else
1250 color = setRGBA (QColor (val).rgba (), opacity);
1251 }
1252
setOpacity(const QString & val)1253 void SmilColorProperty::setOpacity (const QString &val)
1254 {
1255 opacity = SizeType (val, true).size (100);
1256 color = setRGBA (color, opacity);
1257 }
1258
parseBackgroundParam(SmilColorProperty & p,const TrieString & name,const QString & val)1259 static bool parseBackgroundParam (SmilColorProperty &p, const TrieString &name, const QString &val)
1260 {
1261 if (name == "background-color" || name == "backgroundColor")
1262 p.setColor (val);
1263 else if (name == "backgroundOpacity")
1264 p.setOpacity (val);
1265 else
1266 return false;
1267 return true;
1268 }
1269
init()1270 void MediaOpacity::init () {
1271 bg_opacity = opacity = 100;
1272 }
1273
parseMediaOpacityParam(MediaOpacity & p,const TrieString & name,const QString & val)1274 static bool parseMediaOpacityParam (MediaOpacity &p, const TrieString &name, const QString &val) {
1275 if (name == "mediaOpacity")
1276 p.opacity = (int) SizeType (val, true).size (100);
1277 else if (name == "mediaBackgroundOpacity")
1278 p.bg_opacity = (int) SizeType (val, true).size (100);
1279 else
1280 return false;
1281 return true;
1282 }
1283
init()1284 void TransitionModule::init () {
1285 trans_out_active = false;
1286 trans_start_time = 0;
1287 }
1288
cancelTimer(Node * n)1289 void TransitionModule::cancelTimer (Node *n) {
1290 if (trans_out_timer) {
1291 n->document ()->cancelPosting (trans_out_timer);
1292 trans_out_timer = NULL;
1293 }
1294 }
1295
begin(Node * n,Runtime * runtime)1296 void TransitionModule::begin (Node *n, Runtime *runtime)
1297 {
1298 SMIL::Transition *trans = convertNode <SMIL::Transition> (trans_in);
1299 if (trans && trans->supported ()) {
1300 active_trans = trans_in;
1301 runtime->timingstate = Runtime::TimingsTransIn;
1302 trans_gain = 0.0;
1303 transition_updater.connect (n->document (), MsgSurfaceUpdate, n);
1304 trans_start_time = n->document ()->last_event_time;
1305 trans_end_time = trans_start_time + 10 * trans->dur;
1306 if (Runtime::DurTimer == runtime->durTime ().durval &&
1307 0 == runtime->durTime ().offset &&
1308 Runtime::DurMedia == runtime->endTime ().durval)
1309 runtime->durTime ().durval = Runtime::DurTransition;
1310 }
1311 if (Runtime::DurTimer == runtime->durTime().durval &&
1312 runtime->durTime().offset > 0) {
1313 // FIXME: also account for fill duration
1314 trans = convertNode <SMIL::Transition> (trans_out);
1315 if (trans && trans->supported () &&
1316 (int) trans->dur < runtime->durTime().offset)
1317 trans_out_timer = n->document()->post (n,
1318 new TimerPosting ((runtime->durTime().offset - trans->dur) * 10,
1319 trans_out_timer_id));
1320 }
1321 }
1322
handleMessage(Node * n,Runtime * runtime,Surface * s,MessageType msg,void * content)1323 bool TransitionModule::handleMessage (Node *n, Runtime *runtime, Surface *s,
1324 MessageType msg, void *content) {
1325 switch (msg) {
1326 case MsgSurfaceUpdate: {
1327 UpdateEvent *ue = static_cast <UpdateEvent *> (content);
1328
1329 trans_start_time += ue->skipped_time;
1330 trans_end_time += ue->skipped_time;
1331
1332 trans_gain = 1.0 * (ue->cur_event_time - trans_start_time) /
1333 (trans_end_time - trans_start_time);
1334 if (trans_gain > 0.9999) {
1335 transition_updater.disconnect ();
1336 if (active_trans == trans_in) {
1337 runtime->timingstate = Runtime::timings_started;
1338 n->deliver (MsgChildTransformedIn, n);
1339 }
1340 if (!trans_out_active)
1341 active_trans = NULL;
1342 trans_gain = 1.0;
1343 if (Runtime::DurTransition == runtime->durTime ().durval) {
1344 runtime->durTime ().durval = Runtime::DurTimer;
1345 runtime->tryFinish ();
1346 }
1347 }
1348 if (s && s->parentNode())
1349 s->parentNode()->repaint (s->bounds);
1350 return true;
1351 }
1352
1353 case MsgEventTimer: {
1354 TimerPosting *te = static_cast <TimerPosting *> (content);
1355 if (te->event_id == trans_out_timer_id) {
1356 if (active_trans)
1357 transition_updater.disconnect ();
1358 trans_out_timer = NULL;
1359 active_trans = trans_out;
1360 SMIL::Transition *trans = convertNode<SMIL::Transition> (trans_out);
1361 if (trans) {
1362 trans_gain = 0.0;
1363 transition_updater.connect (n->document(), MsgSurfaceUpdate, n);
1364 trans_start_time = n->document ()->last_event_time;
1365 trans_end_time = trans_start_time + 10 * trans->dur;
1366 trans_out_active = true;
1367 if (s)
1368 s->repaint ();
1369 }
1370 return true;
1371 }
1372 break;
1373 }
1374 default:
1375 break;
1376 }
1377 return false;
1378 }
1379
finish(Node * n)1380 void TransitionModule::finish (Node *n) {
1381 transition_updater.disconnect ();
1382 cancelTimer (n);
1383 }
1384
1385 //-----------------------------------------------------------------------------
1386
childFromTag(const QString & tag)1387 KDE_NO_EXPORT Node *SMIL::Smil::childFromTag (const QString & tag) {
1388 QByteArray ba = tag.toLatin1 ();
1389 const char *ctag = ba.constData ();
1390 if (!strcmp (ctag, "body"))
1391 return new SMIL::Body (m_doc);
1392 else if (!strcmp (ctag, "head"))
1393 return new SMIL::Head (m_doc);
1394 return NULL;
1395 }
1396
activate()1397 KDE_NO_EXPORT void SMIL::Smil::activate () {
1398 resolved = true;
1399 if (layout_node)
1400 Element::activate ();
1401 else
1402 Element::deactivate(); // some unfortunate reset in parent doc
1403 }
1404
deactivate()1405 KDE_NO_EXPORT void SMIL::Smil::deactivate () {
1406 Mrl::deactivate ();
1407 }
1408
message(MessageType msg,void * content)1409 KDE_NO_EXPORT void SMIL::Smil::message (MessageType msg, void *content) {
1410 switch (msg) {
1411
1412 case MsgChildFinished: {
1413 Posting *post = (Posting *) content;
1414 if (unfinished ()) {
1415 if (post->source->nextSibling ())
1416 post->source->nextSibling ()->activate ();
1417 else {
1418 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
1419 if (e->active ())
1420 e->deactivate ();
1421 finish ();
1422 }
1423 }
1424 break;
1425 }
1426
1427 case MsgSurfaceBoundsUpdate: {
1428 Layout *layout = convertNode <SMIL::Layout> (layout_node);
1429 if (layout && layout->root_layout)
1430 layout->root_layout->message (msg, content);
1431 return;
1432 }
1433
1434 default:
1435 Mrl::message (msg, content);
1436 }
1437 }
1438
closed()1439 KDE_NO_EXPORT void SMIL::Smil::closed () {
1440 Node *head = findHeadNode (this);
1441 if (!head) {
1442 head = new SMIL::Head (m_doc);
1443 insertBefore (head, firstChild ());
1444 head->setAuxiliaryNode (true);
1445 head->closed ();
1446 }
1447 for (Node *e = head->firstChild (); e; e = e->nextSibling ()) {
1448 if (e->id == id_node_layout) {
1449 layout_node = e;
1450 } else if (e->id == id_node_title) {
1451 QString str = e->innerText ();
1452 title = str.left (str.indexOf (QChar ('\n')));
1453 } else if (e->id == id_node_state) {
1454 state_node = e;
1455 } else if (e->id == id_node_meta) {
1456 Element *elm = static_cast <Element *> (e);
1457 const QString name = elm->getAttribute (Ids::attr_name);
1458 if (name == QString::fromLatin1 ("title"))
1459 title = elm->getAttribute ("content");
1460 else if (name == QString::fromLatin1 ("base"))
1461 src = elm->getAttribute ("content");
1462 }
1463 }
1464 Mrl::closed ();
1465 }
1466
role(RoleType msg,void * content)1467 void *SMIL::Smil::role (RoleType msg, void *content)
1468 {
1469 if (RolePlaylist == msg)
1470 return !title.isEmpty () || //return false if no title and only one
1471 previousSibling () || nextSibling () ? (PlaylistRole *) this : NULL;
1472 return Mrl::role (msg, content);
1473 }
1474
jump(const QString & id)1475 void SMIL::Smil::jump (const QString & id) {
1476 Node *n = document ()->getElementById (this, id, false);
1477 if (n) {
1478 if (n->unfinished ())
1479 kDebug() << "Smil::jump node is unfinished " << id;
1480 else {
1481 for (Node *p = n; p; p = p->parentNode ()) {
1482 if (p->unfinished () &&
1483 p->id >= id_node_first_group &&
1484 p->id <= id_node_last_group) {
1485 static_cast <GroupBase *> (p)->setJumpNode (n);
1486 break;
1487 }
1488 if (n->id == id_node_body || n->id == id_node_smil) {
1489 kError() << "Smil::jump node passed body for " <<id<< endl;
1490 break;
1491 }
1492 }
1493 }
1494 }
1495 }
1496
findSmilNode(Node * node)1497 SMIL::Smil * SMIL::Smil::findSmilNode (Node * node) {
1498 for (Node * e = node; e; e = e->parentNode ())
1499 if (e->id == SMIL::id_node_smil)
1500 return static_cast <SMIL::Smil *> (e);
1501 return 0L;
1502 }
1503
exprStringValue(Node * node,const QString & str)1504 static QString exprStringValue (Node *node, const QString &str) {
1505 Expression* res = evaluateExpr(str.toUtf8(), "data");
1506 if (res) {
1507 SMIL::Smil *smil = SMIL::Smil::findSmilNode (node);
1508 res->setRoot (smil ? smil->state_node.ptr() : NULL);
1509 QString s = res->toString();
1510 delete res;
1511 return s;
1512 }
1513 return str;
1514 }
1515
applySubstitution(Node * n,const QString & str,int p,int q)1516 static QString applySubstitution (Node *n, const QString &str, int p, int q) {
1517 QString s = exprStringValue (n, str.mid (p + 1, q - p - 1));
1518 return str.left (p) + s + str.mid (q + 1 );
1519 }
1520
1521 //-----------------------------------------------------------------------------
1522
headChildDone(Node * node,Node * child)1523 static void headChildDone (Node *node, Node *child) {
1524 if (node->unfinished ()) {
1525 if (child && child->nextSibling ())
1526 child->nextSibling ()->activate ();
1527 else
1528 node->finish (); // we're done
1529 }
1530 }
1531
childFromTag(const QString & tag)1532 KDE_NO_EXPORT Node *SMIL::Head::childFromTag (const QString & tag) {
1533 QByteArray ba = tag.toLatin1 ();
1534 const char *ctag = ba.constData ();
1535 if (!strcmp (ctag, "layout"))
1536 return new SMIL::Layout (m_doc);
1537 else if (!strcmp (ctag, "title"))
1538 return new DarkNode (m_doc, ctag, id_node_title);
1539 else if (!strcmp (ctag, "meta"))
1540 return new DarkNode (m_doc, ctag, id_node_meta);
1541 else if (!strcmp (ctag, "state"))
1542 return new SMIL::State (m_doc);
1543 else if (!strcmp (ctag, "transition"))
1544 return new SMIL::Transition (m_doc);
1545 return NULL;
1546 }
1547
closed()1548 KDE_NO_EXPORT void SMIL::Head::closed () {
1549 for (Node *e = firstChild (); e; e = e->nextSibling ())
1550 if (e->id == id_node_layout)
1551 return;
1552 SMIL::Layout * layout = new SMIL::Layout (m_doc);
1553 appendChild (layout);
1554 layout->setAuxiliaryNode (true);
1555 layout->closed (); // add root-layout and a region
1556 Element::closed ();
1557 }
1558
message(MessageType msg,void * content)1559 KDE_NO_EXPORT void SMIL::Head::message (MessageType msg, void *content) {
1560 if (MsgChildFinished == msg) {
1561 headChildDone (this, ((Posting *) content)->source.ptr ());
1562 return;
1563 }
1564 Element::message (msg, content);
1565 }
1566
1567 //-----------------------------------------------------------------------------
1568
State(NodePtr & d)1569 SMIL::State::State (NodePtr &d)
1570 : Element (d, id_node_state), media_info (NULL) {}
1571
childFromTag(const QString & tag)1572 Node *SMIL::State::childFromTag (const QString &tag) {
1573 if (tag == "data")
1574 return new DarkNode (m_doc, tag.toUtf8 (), SMIL::id_node_state_data);
1575 return NULL;
1576 }
1577
closed()1578 void SMIL::State::closed () {
1579 if (!firstChild ()) {
1580 appendChild (new DarkNode (m_doc, "data", SMIL::id_node_state_data));
1581 firstChild ()->setAuxiliaryNode (true);
1582 }
1583 }
1584
activate()1585 KDE_NO_EXPORT void SMIL::State::activate () {
1586 init ();
1587 Element::activate ();
1588 }
1589
1590 KDE_NO_EXPORT
parseParam(const TrieString & name,const QString & val)1591 void SMIL::State::parseParam (const TrieString &name, const QString &val) {
1592 if (name == Ids::attr_src) {
1593 Smil *s = val.isEmpty () ? NULL : SMIL::Smil::findSmilNode (this);
1594 if (s) {
1595 m_url.clear ();
1596 if (!media_info)
1597 media_info = new MediaInfo (this, MediaManager::Text);
1598 Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
1599 QString url = mrl ? KURL (mrl->absolutePath(), val).url() : val;
1600 postpone_lock = document ()->postpone ();
1601 media_info->wget (url, domain ());
1602 m_url = url;
1603 }
1604 } else {
1605 Element::parseParam (name, val);
1606 }
1607 }
1608
deactivate()1609 KDE_NO_EXPORT void SMIL::State::deactivate () {
1610 delete media_info;
1611 media_info = NULL;
1612 postpone_lock = NULL;
1613 Element::deactivate ();
1614 m_url.clear ();
1615 }
1616
domain()1617 QString SMIL::State::domain () {
1618 QString s = m_url;
1619 if (s.isEmpty ()) {
1620 for (Node *p = parentNode (); p; p = p->parentNode ()) {
1621 Mrl *m = p->mrl ();
1622 if (m && !m->src.isEmpty () && m->src != "Playlist://") {
1623 s = m->absolutePath ();
1624 break;
1625 }
1626 }
1627 }
1628 KUrl url (s);
1629 if (url.isLocalFile ())
1630 return QString ();
1631 return url.protocol () + "://" + url.host ();
1632 }
1633
stateChanged(Node * ref)1634 void SMIL::State::stateChanged (Node *ref) {
1635 Connection *c = m_StateChangeListeners.first ();
1636 for (; c; c = m_StateChangeListeners.next ()) {
1637 if (c->payload && c->connecter) {
1638 Expression *expr = (Expression *) c->payload;
1639 expr->setRoot (this);
1640 Expression::iterator it, e = expr->end();
1641 for (it = expr->begin(); it != e; ++it) {
1642 if (it->node == ref)
1643 document()->post (c->connecter,
1644 new Posting (this, MsgStateChanged, expr));
1645 }
1646 }
1647 }
1648 }
1649
setValue(Node * ref,const QString & value)1650 void SMIL::State::setValue (Node *ref, const QString &value) {
1651 const QString old = ref->nodeValue ();
1652 const QString s = exprStringValue (this, value);
1653 ref->clearChildren ();
1654 if (!s.isEmpty ())
1655 ref->appendChild (new TextNode (m_doc, s));
1656 if (s != old)
1657 stateChanged (ref);
1658 }
1659
newValue(Node * ref,Where where,const QString & name,const QString & value)1660 void SMIL::State::newValue (Node *ref, Where where,
1661 const QString &name, const QString &value) {
1662 NodePtr n = new DarkNode (m_doc, name.toUtf8 ());
1663 switch (where) {
1664 case before:
1665 ref->parentNode ()->insertBefore (n, ref);
1666 break;
1667 case after:
1668 ref->parentNode ()->insertBefore (n, ref->nextSibling ());
1669 break;
1670 default:
1671 ref->appendChild (n);
1672 }
1673 if (!value.isEmpty ()) {
1674 const QString s = exprStringValue (this, value);
1675 n->appendChild (new TextNode (m_doc, s));
1676 stateChanged (ref);
1677 }
1678 }
1679
message(MessageType msg,void * content)1680 void SMIL::State::message (MessageType msg, void *content) {
1681 switch (msg) {
1682
1683 case MsgMediaReady:
1684 if (media_info && media_info->media) {
1685 if (firstChild ())
1686 removeChild (firstChild ());
1687 QTextStream in (&((TextMedia *)media_info->media)->text);
1688 readXML (this, in, QString ());
1689 if (firstChild ())
1690 stateChanged (firstChild ());
1691 }
1692 delete media_info;
1693 media_info = NULL;
1694 postpone_lock = NULL;
1695 return;
1696
1697 default:
1698 break;
1699 }
1700 Element::message (msg, content);
1701 }
1702
role(RoleType msg,void * content)1703 void *SMIL::State::role (RoleType msg, void *content) {
1704 if (MsgStateChanged == (MessageType) (long) content)
1705 return &m_StateChangeListeners;
1706 return Element::role (msg, content);
1707 }
1708
1709 //-----------------------------------------------------------------------------
1710
Layout(NodePtr & d)1711 KDE_NO_CDTOR_EXPORT SMIL::Layout::Layout (NodePtr & d)
1712 : Element (d, id_node_layout) {}
1713
childFromTag(const QString & tag)1714 KDE_NO_EXPORT Node *SMIL::Layout::childFromTag (const QString & tag) {
1715 QByteArray ba = tag.toLatin1 ();
1716 const char *ctag = ba.constData ();
1717 if (!strcmp (ctag, "root-layout")) {
1718 Node *e = new SMIL::RootLayout (m_doc);
1719 root_layout = e;
1720 return e;
1721 } else if (!strcmp (ctag, "region"))
1722 return new SMIL::Region (m_doc);
1723 else if (!strcmp (ctag, "regPoint"))
1724 return new SMIL::RegPoint (m_doc);
1725 return NULL;
1726 }
1727
closed()1728 KDE_NO_EXPORT void SMIL::Layout::closed () {
1729 if (!root_layout) { // just add one if none there
1730 root_layout = new SMIL::RootLayout (m_doc);
1731 root_layout->setAuxiliaryNode (true);
1732 insertBefore (root_layout, firstChild ());
1733 root_layout->closed ();
1734 } else if (root_layout.ptr () != firstChild ()) {
1735 NodePtr rl = root_layout;
1736 removeChild (root_layout);
1737 insertBefore (root_layout, firstChild ());
1738 }
1739 Element::closed ();
1740 }
1741
message(MessageType msg,void * content)1742 KDE_NO_EXPORT void SMIL::Layout::message (MessageType msg, void *content) {
1743 if (MsgChildFinished == msg) {
1744 headChildDone (this, ((Posting *) content)->source.ptr ());
1745 if (state_finished == state && root_layout)
1746 root_layout->message (MsgSurfaceBoundsUpdate, (void *) true);
1747 return;
1748 }
1749 Element::message (msg, content);
1750 }
1751
1752 //-----------------------------------------------------------------------------
1753
RegionBase(NodePtr & d,short id)1754 KDE_NO_CDTOR_EXPORT SMIL::RegionBase::RegionBase (NodePtr & d, short id)
1755 : Element (d, id),
1756 media_info (NULL),
1757 z_order (0)
1758 {}
1759
~RegionBase()1760 KDE_NO_CDTOR_EXPORT SMIL::RegionBase::~RegionBase () {
1761 if (region_surface)
1762 region_surface->remove ();
1763 }
1764
activate()1765 KDE_NO_EXPORT void SMIL::RegionBase::activate () {
1766 show_background = ShowAlways;
1767 background_color.init ();
1768 media_opacity.init ();
1769 bg_repeat = BgRepeat;
1770 fit = fit_default;
1771 Node *n = parentNode ();
1772 if (n && SMIL::id_node_layout == n->id)
1773 n = n->firstChild ();
1774 state = state_deferred;
1775 role (RoleDisplay);
1776 font_props.init ();
1777 init ();
1778 Element::activate ();
1779 }
1780
deactivate()1781 KDE_NO_EXPORT void SMIL::RegionBase::deactivate () {
1782 show_background = ShowAlways;
1783 background_color.init ();
1784 background_image.truncate (0);
1785 if (media_info) {
1786 delete media_info;
1787 media_info = NULL;
1788 }
1789 postpone_lock = NULL;
1790 sizes.resetSizes ();
1791 Element::deactivate ();
1792 }
1793
dataArrived()1794 KDE_NO_EXPORT void SMIL::RegionBase::dataArrived () {
1795 ImageMedia *im = media_info ? (ImageMedia *)media_info->media : NULL;
1796 if (im && !im->isEmpty () && region_surface) {
1797 region_surface->markDirty ();
1798 region_surface->repaint ();
1799 }
1800 postpone_lock = 0L;
1801 }
1802
repaint()1803 KDE_NO_EXPORT void SMIL::RegionBase::repaint () {
1804 Surface *s = (Surface *) role (RoleDisplay);
1805 if (s)
1806 s->repaint ();
1807 }
1808
repaint(const SRect & rect)1809 KDE_NO_EXPORT void SMIL::RegionBase::repaint (const SRect & rect) {
1810 Surface *s = (Surface *) role (RoleDisplay);
1811 if (s)
1812 s->repaint (SRect (0, 0, s->bounds.size).intersect (rect));
1813 }
1814
updateSurfaceSort(SMIL::RegionBase * rb)1815 static void updateSurfaceSort (SMIL::RegionBase *rb) {
1816 Surface *rs = rb->region_surface.ptr ();
1817 Surface *prs = rs->parentNode ();
1818 Surface *next = NULL;
1819 if (!prs)
1820 return;
1821 for (Surface *s = prs->firstChild (); s; s = s->nextSibling ())
1822 if (s != rs && s->node) {
1823 if (SMIL::id_node_region == s->node->id) {
1824 SMIL::Region *r = static_cast <SMIL::Region *> (s->node.ptr ());
1825 if (r->z_order > rb->z_order) {
1826 next = s;
1827 break;
1828 } else if (r->z_order == rb->z_order) {
1829 next = s;
1830 // now take region order into account
1831 Node *n = rb->previousSibling();
1832 for (; n; n = n->previousSibling())
1833 if (n->id == SMIL::id_node_region) {
1834 r = static_cast <SMIL::Region *> (n);
1835 if (r->region_surface && r->z_order == rb->z_order) {
1836 next = r->region_surface->nextSibling ();
1837 if (rs == next)
1838 next = next->nextSibling ();
1839 break;
1840 }
1841 }
1842 break;
1843 }
1844 } else if (SMIL::id_node_root_layout != s->node->id) {
1845 // break at attached media types
1846 Surface *m = (Surface *) s->node->role (RoleDisplay);
1847 if (m) {
1848 next = m;
1849 break;
1850 }
1851 }
1852 }
1853 if (rs->nextSibling () == next) {
1854 return;
1855 }
1856 SurfacePtr protect (rs);
1857 prs->removeChild (rs);
1858 prs->insertBefore (rs, next);
1859 }
1860
1861 KDE_NO_EXPORT
parseParam(const TrieString & name,const QString & val)1862 void SMIL::RegionBase::parseParam (const TrieString & name, const QString & val) {
1863 bool need_repaint = false;
1864 if (name == Ids::attr_fit) {
1865 Fit ft = parseFit (val.toAscii ().constData ());
1866 if (ft != fit) {
1867 fit = ft;
1868 if (region_surface)
1869 region_surface->scroll = fit_scroll == fit;
1870 need_repaint = true;
1871 }
1872 } else if (parseBackgroundParam (background_color, name, val) ||
1873 parseMediaOpacityParam (media_opacity, name, val)) {
1874 } else if (name == "z-index") {
1875 z_order = val.toInt ();
1876 if (region_surface)
1877 updateSurfaceSort (this);
1878 need_repaint = true;
1879 } else if (sizes.setSizeParam (name, val)) {
1880 if (state_finished == state && region_surface)
1881 message (MsgSurfaceBoundsUpdate);
1882 } else if (name == "showBackground") {
1883 if (val == "whenActive")
1884 show_background = ShowWhenActive;
1885 else
1886 show_background = ShowAlways;
1887 need_repaint = true;
1888 } else if (name == "backgroundRepeat") {
1889 if (val == "noRepeat")
1890 bg_repeat = BgNoRepeat;
1891 else if (val == "repeatX")
1892 bg_repeat = BgRepeatX;
1893 else if (val == "repeatY")
1894 bg_repeat = BgRepeatY;
1895 else if (val == "inherit")
1896 bg_repeat = BgInherit;
1897 else
1898 bg_repeat = BgRepeat;
1899 } else if (name == "backgroundImage") {
1900 if (val.isEmpty () || val == "none" || val == "inherit") {
1901 need_repaint = !background_image.isEmpty () &&
1902 background_image != val;
1903 background_image = val;
1904 if (media_info) {
1905 delete media_info;
1906 media_info = NULL;
1907 postpone_lock = NULL;
1908 }
1909 } else if (background_image != val) {
1910 background_image = val;
1911 Smil *s = val.isEmpty () ? NULL : SMIL::Smil::findSmilNode (this);
1912 if (s) {
1913 if (!media_info)
1914 media_info = new MediaInfo (this, MediaManager::Image);
1915 Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
1916 QString url = mrl ? KURL (mrl->absolutePath(), val).url() : val;
1917 postpone_lock = document ()->postpone ();
1918 media_info->wget (url);
1919 }
1920 }
1921 } else {
1922 font_props.parseParam (name, val);
1923 }
1924 if (active ()) {
1925 Surface *s = (Surface *) role (RoleDisplay);
1926 if (s && s->background_color != background_color.color){
1927 s->setBackgroundColor (background_color.color);
1928 need_repaint = true;
1929 }
1930 if (need_repaint && s)
1931 s->repaint ();
1932 }
1933 Element::parseParam (name, val);
1934 }
1935
message(MessageType msg,void * content)1936 void SMIL::RegionBase::message (MessageType msg, void *content) {
1937 switch (msg) {
1938
1939 case MsgMediaReady:
1940 if (media_info)
1941 dataArrived ();
1942 return;
1943
1944 case MsgChildFinished:
1945 headChildDone (this, ((Posting *) content)->source.ptr ());
1946 return;
1947
1948 default:
1949 break;
1950 }
1951 Element::message (msg, content);
1952 }
1953
role(RoleType msg,void * content)1954 void *SMIL::RegionBase::role (RoleType msg, void *content) {
1955 switch (msg) {
1956
1957 case RoleSizer:
1958 return &sizes;
1959
1960 case RoleReceivers:
1961 if (MsgSurfaceAttach == (MessageType) (long) content)
1962 return &m_AttachedMediaTypes;
1963 // fall through
1964
1965 default:
1966 break;
1967 }
1968 return Element::role (msg, content);
1969 }
1970
1971
1972 //--------------------------%<-------------------------------------------------
1973
closed()1974 KDE_NO_EXPORT void SMIL::RootLayout::closed () {
1975 QString width = getAttribute (Ids::attr_width);
1976 QString height = getAttribute (Ids::attr_height);
1977 if (!width.isEmpty () && !height.isEmpty ()) {
1978 Smil *s = Smil::findSmilNode (this);
1979 if (s) {
1980 s->size.width = width.toDouble ();
1981 s->size.height = height.toDouble();
1982 }
1983 }
1984 Element::closed ();
1985 }
1986
~RootLayout()1987 KDE_NO_CDTOR_EXPORT SMIL::RootLayout::~RootLayout() {
1988 }
1989
deactivate()1990 KDE_NO_EXPORT void SMIL::RootLayout::deactivate () {
1991 SMIL::Smil *s = Smil::findSmilNode (this);
1992 if (s)
1993 s->role (RoleChildDisplay, NULL);
1994 if (region_surface) {
1995 region_surface->remove ();
1996 region_surface = NULL;
1997 }
1998 RegionBase::deactivate ();
1999 }
2000
message(MessageType msg,void * content)2001 void SMIL::RootLayout::message (MessageType msg, void *content) {
2002 switch (msg) {
2003
2004 case MsgSurfaceBoundsUpdate:
2005 if (region_surface) {
2006 Surface *surface = region_surface.ptr ();
2007 Surface *ps = surface->parentNode ();
2008 Single x, y, w, h, pw, ph;
2009 if (ps && auxiliaryNode ()) {
2010 w = ps->bounds.width ();
2011 h = ps->bounds.height ();
2012 sizes.width = QString::number ((int) w);
2013 sizes.height = QString::number ((int) h);
2014 } else {
2015 w = sizes.width.size ();
2016 h = sizes.height.size ();
2017 if (ps) {
2018 pw = ps->bounds.width ();
2019 ph = ps->bounds.height ();
2020 double pasp = (double) pw / ph;
2021 double asp = (double) w / h;
2022 if (pasp > asp) {
2023 ps->xscale = ps->yscale = 1.0 * ph / h;
2024 x += (Single (pw/ps->yscale) - w) / 2;
2025 } else {
2026 ps->xscale = ps->yscale = 1.0 * pw / w;
2027 y += (Single (ph/ps->xscale) - h) / 2;
2028 }
2029 }
2030 }
2031 if (content || surface->bounds.size != SSize (w, h)) {
2032 surface->bounds = SRect (x, y, w, h);
2033 if (!auxiliaryNode ()) {
2034 SMIL::Smil *s = Smil::findSmilNode (this);
2035 s->size = surface->bounds.size;
2036 }
2037 if (content)
2038 surface->resize (surface->bounds, true);
2039 else
2040 surface->updateChildren (!!content);
2041 }
2042 }
2043 return;
2044
2045 default:
2046 break;
2047 }
2048 RegionBase::message (msg, content);
2049 }
2050
role(RoleType msg,void * content)2051 void *SMIL::RootLayout::role (RoleType msg, void *content) {
2052 switch (msg) {
2053
2054 case RoleDisplay:
2055 if (!region_surface && active ()) {
2056 SMIL::Smil *s = Smil::findSmilNode (this);
2057 if (s && s->active ()) {
2058 Surface *surface = (Surface *)s->role (RoleChildDisplay, s);
2059 if (surface) {
2060 region_surface = surface->createSurface (this, SRect ());
2061 // FIXME, silly heuristic to allow transparency in nesting
2062 if (!background_color.color
2063 && (!s->parentNode ()
2064 || s->parentNode()->id < id_node_smil))
2065 background_color.color = 0xFFFFFAFA; // snow
2066 }
2067 }
2068 }
2069 return region_surface.ptr ();
2070
2071 default:
2072 break;
2073 }
2074 return RegionBase::role (msg, content);
2075 }
2076
2077 //--------------------------%<-------------------------------------------------
2078
Region(NodePtr & d)2079 KDE_NO_CDTOR_EXPORT SMIL::Region::Region (NodePtr & d)
2080 : RegionBase (d, id_node_region) {}
2081
~Region()2082 KDE_NO_CDTOR_EXPORT SMIL::Region::~Region () {
2083 }
2084
deactivate()2085 KDE_NO_EXPORT void SMIL::Region::deactivate () {
2086 if (region_surface)
2087 region_surface->remove ();
2088 RegionBase::deactivate ();
2089 }
2090
childFromTag(const QString & tag)2091 KDE_NO_EXPORT Node *SMIL::Region::childFromTag (const QString & tag) {
2092 if (!strcmp (tag.toLatin1 ().constData (), "region"))
2093 return new SMIL::Region (m_doc);
2094 return NULL;
2095 }
2096
message(MessageType msg,void * content)2097 void SMIL::Region::message (MessageType msg, void *content) {
2098 switch (msg) {
2099
2100 case MsgSurfaceBoundsUpdate:
2101 if (region_surface && state == state_finished) {
2102 Surface *ps = region_surface->parentNode ();
2103 if (ps) {
2104 SSize dim = ps->bounds.size;
2105 Single x, y, w, h;
2106 sizes.calcSizes (this, NULL, dim.width, dim.height, x, y, w, h);
2107 region_surface->resize (SRect (x, y, w, h), !!content);
2108 }
2109 }
2110 return;
2111
2112 default:
2113 break;
2114 }
2115 RegionBase::message (msg, content);
2116 }
2117
role(RoleType msg,void * content)2118 void *SMIL::Region::role (RoleType msg, void *content) {
2119 switch (msg) {
2120
2121 case RoleDisplay:
2122 if (!region_surface && active ()) {
2123 Node *n = parentNode ();
2124 if (n && SMIL::id_node_layout == n->id)
2125 n = n->firstChild ();
2126 Surface *s = (Surface *) n->role (RoleDisplay);
2127 if (s) {
2128 region_surface = s->createSurface (this, SRect ());
2129 region_surface->background_color = background_color.color;
2130 updateSurfaceSort (this);
2131 }
2132 }
2133 return region_surface.ptr ();
2134
2135 default: {
2136 ConnectionList *l = mouse_listeners.receivers ((MessageType)(long)content);
2137 if (l)
2138 return l;
2139 }
2140 }
2141 return RegionBase::role (msg, content);
2142 }
2143
2144
2145 //-----------------------------------------------------------------------------
2146
2147 KDE_NO_EXPORT
parseParam(const TrieString & p,const QString & v)2148 void SMIL::RegPoint::parseParam (const TrieString & p, const QString & v) {
2149 sizes.setSizeParam (p, v); // TODO: if dynamic, make sure to repaint
2150 Element::parseParam (p, v);
2151 }
2152
2153 //-----------------------------------------------------------------------------
2154
2155 static struct TransTypeInfo {
2156 const char *name;
2157 SMIL::Transition::TransType type;
2158 short sub_types;
2159 SMIL::Transition::TransSubType sub_type[8];
2160 } transition_type_info[] = {
2161 #include "transitions.txt"
2162 };
2163
2164 static struct SubTransTypeInfo {
2165 const char *name;
2166 SMIL::Transition::TransSubType sub_type;
2167 } sub_transition_type_info[] = {
2168 #include "subtrans.txt"
2169 };
2170
transInfoFromString(const char * t)2171 static TransTypeInfo *transInfoFromString (const char *t) {
2172 // TODO binary search
2173 for (int i = 0; transition_type_info[i].name; ++i)
2174 if (!strcmp (t, transition_type_info[i].name))
2175 return transition_type_info + i;
2176 return NULL;
2177 }
2178
2179 static
subTransInfoFromString(const char * s)2180 SMIL::Transition::TransSubType subTransInfoFromString (const char *s) {
2181 for (int i = 0; sub_transition_type_info[i].name; ++i)
2182 if (!strcmp (s, sub_transition_type_info[i].name))
2183 return sub_transition_type_info[i].sub_type;
2184 return SMIL::Transition::SubTransTypeNone;
2185 }
2186
Transition(NodePtr & d)2187 KDE_NO_CDTOR_EXPORT SMIL::Transition::Transition (NodePtr & d)
2188 : Element (d, id_node_transition),
2189 type_info (NULL), direction (dir_forward), dur (100), fade_color (0) {}
2190
activate()2191 KDE_NO_EXPORT void SMIL::Transition::activate () {
2192 type = TransTypeNone;
2193 sub_type = SubTransTypeNone;
2194 start_progress = 0.0;
2195 end_progress = 1.0;
2196 type_info = NULL;
2197 init ();
2198 Element::activate ();
2199 }
2200
2201 KDE_NO_EXPORT
parseParam(const TrieString & para,const QString & val)2202 void SMIL::Transition::parseParam (const TrieString & para, const QString & val) {
2203 if (para == Ids::attr_type) {
2204 type_info = transInfoFromString (val.toAscii ().constData ());
2205 if (type_info) {
2206 type = type_info->type;
2207 if (SubTransTypeNone != sub_type) {
2208 for (int i = 0; i < type_info->sub_types; ++i)
2209 if (type_info->sub_type[i] == sub_type)
2210 return;
2211 }
2212 if (type_info->sub_types > 0)
2213 sub_type = type_info->sub_type[0];
2214 }
2215 } else if (para == Ids::attr_dur) {
2216 parseTime (val, dur);
2217 } else if (para == "subtype") {
2218 sub_type = subTransInfoFromString (val.toAscii ().constData ());
2219 if (type_info) {
2220 if (SubTransTypeNone != sub_type) {
2221 for (int i = 0; i < type_info->sub_types; ++i)
2222 if (type_info->sub_type[i] == sub_type)
2223 return;
2224 }
2225 if (type_info->sub_types > 0)
2226 sub_type = type_info->sub_type[0];
2227 }
2228 } else if (para == "fadeColor") {
2229 fade_color = QColor (getAttribute (val)).rgb ();
2230 } else if (para == "direction") {
2231 direction = val == "reverse" ? dir_reverse : dir_forward;
2232 } else if (para == "startProgress") {
2233 start_progress = val.toDouble();
2234 if (start_progress < 0.0)
2235 start_progress = 0.0;
2236 else if (start_progress > 1.0)
2237 start_progress = 1.0;
2238 } else if (para == "endProgress") {
2239 end_progress = val.toDouble();
2240 if (end_progress < start_progress)
2241 end_progress = start_progress;
2242 else if (end_progress > 1.0)
2243 end_progress = 1.0;
2244 } else {
2245 Element::parseParam (para, val);
2246 }
2247 }
2248
supported()2249 KDE_NO_EXPORT bool SMIL::Transition::supported () {
2250 switch (type) {
2251 case Fade:
2252 case BarWipe:
2253 case BowTieWipe:
2254 case PushWipe:
2255 case IrisWipe:
2256 case ClockWipe:
2257 case EllipseWipe:
2258 return true;
2259 default:
2260 return false;
2261 }
2262 }
2263
2264 //-----------------------------------------------------------------------------
2265
GroupBase(NodePtr & d,short id)2266 KDE_NO_CDTOR_EXPORT SMIL::GroupBase::GroupBase (NodePtr & d, short id)
2267 : Element (d, id),
2268 runtime (new Runtime (this)) {}
2269
~GroupBase()2270 KDE_NO_CDTOR_EXPORT SMIL::GroupBase::~GroupBase () {
2271 delete runtime;
2272 }
2273
childFromTag(const QString & tag)2274 KDE_NO_EXPORT Node *SMIL::GroupBase::childFromTag (const QString & tag) {
2275 Element * elm = fromScheduleGroup (m_doc, tag);
2276 if (!elm) elm = fromMediaContentGroup (m_doc, tag);
2277 if (!elm) elm = fromContentControlGroup (m_doc, tag);
2278 if (!elm) elm = fromAnimateGroup (m_doc, tag);
2279 if (elm)
2280 return elm;
2281 return NULL;
2282 }
2283
init()2284 KDE_NO_EXPORT void SMIL::GroupBase::init () {
2285 if (Runtime::TimingsInitialized > runtime->timingstate) {
2286 Element::init ();
2287 runtime->initialize ();
2288 }
2289 }
2290
finish()2291 KDE_NO_EXPORT void SMIL::GroupBase::finish () {
2292 setState (state_finished); // avoid recurstion through childDone
2293 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2294 if (e->unfinished ())
2295 e->finish ();
2296 runtime->finish ();
2297 }
2298
2299 namespace {
2300
2301 class KMPLAYER_NO_EXPORT GroupBaseInitVisitor : public Visitor {
2302 public:
2303 using Visitor::visit;
2304
2305 bool ready;
2306
GroupBaseInitVisitor()2307 GroupBaseInitVisitor () : ready (true) {
2308 }
2309
visit(Node * node)2310 void visit (Node *node) {
2311 node->message (MsgMediaPrefetch, MsgBool (1));
2312 }
visit(SMIL::PriorityClass * pc)2313 void visit (SMIL::PriorityClass *pc) {
2314 for (NodePtr n = pc->firstChild (); n; n = n->nextSibling ())
2315 n->accept (this);
2316 }
visit(SMIL::Seq * seq)2317 void visit (SMIL::Seq *seq) {
2318 for (Node *n = seq->firstChild (); n; n = n->nextSibling ())
2319 if (n->role (RoleTiming)) {
2320 seq->firstChild ()->accept (this);
2321 ready = !!seq->firstChild ()->role (RoleReady);
2322 break;
2323 }
2324 }
visit(SMIL::Switch * s)2325 void visit (SMIL::Switch *s) {
2326 Node *n = s->chosenOne ();
2327 if (n)
2328 n->accept (this);
2329 }
visit(SMIL::Anchor * a)2330 void visit (SMIL::Anchor *a) {
2331 if (a->firstChild ())
2332 a->firstChild ()->accept (this);
2333 }
visit(SMIL::Par * par)2334 void visit (SMIL::Par *par) {
2335 for (NodePtr n = par->firstChild (); n; n = n->nextSibling ()) {
2336 n->accept (this);
2337 if (ready)
2338 ready = !!n->role (RoleReady);
2339 }
2340 }
2341 };
2342
2343 class KMPLAYER_NO_EXPORT FreezeStateUpdater : public Visitor {
2344
2345 bool initial_node;
2346 bool freeze;
2347
setFreezeState(Runtime * rt)2348 void setFreezeState (Runtime *rt) {
2349 bool auto_freeze = (Runtime::DurTimer == rt->durTime ().durval &&
2350 0 == rt->durTime ().offset &&
2351 Runtime::DurMedia == rt->endTime ().durval) &&
2352 rt->fill_active != Runtime::fill_remove;
2353 bool cfg_freeze = rt->fill_active == Runtime::fill_freeze ||
2354 rt->fill_active == Runtime::fill_hold ||
2355 rt->fill_active == Runtime::fill_transition;
2356
2357 bool do_freeze = freeze && (auto_freeze || cfg_freeze);
2358 if (do_freeze && rt->timingstate == Runtime::timings_stopped) {
2359 rt->timingstate = Runtime::timings_freezed;
2360 rt->element->message (MsgStateFreeze);
2361 } else if (!do_freeze && rt->timingstate == Runtime::timings_freezed) {
2362 rt->timingstate = Runtime::timings_stopped;
2363 rt->element->message (MsgStateFreeze);
2364 }
2365 }
updateNode(Node * n)2366 void updateNode (Node *n) {
2367 if (initial_node) {
2368 initial_node = false;
2369 } else {
2370 Runtime *rt = (Runtime *) n->role (RoleTiming);
2371 if (rt && rt->timingstate >= Runtime::timings_stopped)
2372 setFreezeState (rt);
2373 }
2374 }
2375 public:
2376 using Visitor::visit;
2377
FreezeStateUpdater()2378 FreezeStateUpdater () : initial_node (true), freeze (true) {}
2379
visit(Element * elm)2380 void visit (Element *elm) {
2381 updateNode (elm);
2382 }
visit(SMIL::PriorityClass * pc)2383 void visit (SMIL::PriorityClass *pc) {
2384 for (NodePtr n = pc->firstChild (); n; n = n->nextSibling ())
2385 n->accept (this);
2386 }
visit(SMIL::Seq * seq)2387 void visit (SMIL::Seq *seq) {
2388 bool old_freeze = freeze;
2389
2390 updateNode (seq);
2391 freeze = freeze && seq->runtime->active ();
2392
2393 Runtime *prev = NULL;
2394 for (NodePtr n = seq->firstChild (); n; n = n->nextSibling ()) {
2395 if (n->active ()) {
2396 Runtime *rt = (Runtime *) n->role (RoleTiming);
2397 if (rt) {
2398 bool prev_freeze = prev && freeze &&
2399 (prev->fill_active == Runtime::fill_hold ||
2400 (prev->fill_active == Runtime::fill_transition &&
2401 Runtime::TimingsTransIn == rt->state ()));
2402 if (rt->timingstate < Runtime::timings_started) {
2403 break;
2404 } else if (rt->timingstate < Runtime::timings_stopped) {
2405 freeze = prev_freeze;
2406 break;
2407 }
2408 if (prev_freeze)
2409 prev->element->accept (this);
2410 if (prev &&
2411 (!prev_freeze ||
2412 prev->timingstate == Runtime::timings_stopped))
2413 prev->element->deactivate();
2414 prev = rt;
2415 }
2416 }
2417 }
2418 if (prev) {
2419 prev->element->accept (this);
2420 if (prev->timingstate == Runtime::timings_stopped)
2421 prev->element->deactivate();
2422 }
2423
2424 freeze = old_freeze;
2425 }
visit(SMIL::Anchor * a)2426 void visit (SMIL::Anchor *a) {
2427 if (a->firstChild ())
2428 a->firstChild ()->accept (this);
2429 }
visit(SMIL::Par * par)2430 void visit (SMIL::Par *par) {
2431 bool old_freeze = freeze;
2432
2433 updateNode (par);
2434 freeze = freeze && par->runtime->active ();
2435
2436 for (NodePtr n = par->firstChild (); n; n = n->nextSibling ())
2437 n->accept (this);
2438
2439 freeze = old_freeze;
2440 }
visit(SMIL::Excl * excl)2441 void visit (SMIL::Excl *excl) {
2442 bool old_freeze = freeze;
2443
2444 updateNode (excl);
2445 bool new_freeze = freeze && excl->runtime->active ();
2446
2447 Node *cur = excl->cur_node.ptr ();
2448 for (NodePtr n = excl->firstChild (); n; n = n->nextSibling ()) {
2449 freeze = new_freeze && n.ptr () == cur;
2450 n->accept (this);
2451 }
2452
2453 freeze = old_freeze;
2454 }
visit(SMIL::Switch * s)2455 void visit (SMIL::Switch *s) {
2456 bool old_freeze = freeze;
2457
2458 updateNode (s);
2459 freeze &= s->runtime->active ();
2460
2461 Node *cur = s->chosenOne ();
2462 if (cur)
2463 cur->accept (this);
2464
2465 freeze = old_freeze;
2466 }
2467 };
2468
2469 }
2470
activate()2471 KDE_NO_EXPORT void SMIL::GroupBase::activate () {
2472 init ();
2473 GroupBaseInitVisitor visitor;
2474 accept (&visitor);
2475 setState (state_activated);
2476 if (visitor.ready)
2477 runtime->start ();
2478 else
2479 state = state_deferred;
2480 }
2481
2482 KDE_NO_EXPORT
parseParam(const TrieString & para,const QString & val)2483 void SMIL::GroupBase::parseParam (const TrieString ¶, const QString &val) {
2484 if (!runtime->parseParam (para, val))
2485 Element::parseParam (para, val);
2486 }
2487
message(MessageType msg,void * content)2488 KDE_NO_EXPORT void SMIL::GroupBase::message (MessageType msg, void *content) {
2489 switch (msg) {
2490
2491 case MsgStateRewind:
2492 if (active ()) {
2493 State old = state;
2494 state = state_deactivated;
2495 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2496 e->reset ();
2497 state = old;
2498 GroupBaseInitVisitor visitor;
2499 accept (&visitor);
2500 }
2501 return;
2502
2503 default:
2504 break;
2505 }
2506 if ((int) msg >= (int) Runtime::DurLastDuration)
2507 Element::message (msg, content);
2508 else
2509 runtime->message (msg, content);
2510 }
2511
role(RoleType msg,void * content)2512 KDE_NO_EXPORT void *SMIL::GroupBase::role (RoleType msg, void *content) {
2513 switch (msg) {
2514
2515 case RoleTiming:
2516 if (Runtime::TimingsInitialized > runtime->timingstate)
2517 init ();
2518 return runtime;
2519
2520 default:
2521 break;
2522 }
2523 void *response = runtime->role (msg, content);
2524 if (response == MsgUnhandled)
2525 return Element::role (msg, content);
2526 return response;
2527 }
2528
2529
deactivate()2530 KDE_NO_EXPORT void SMIL::GroupBase::deactivate () {
2531 bool need_finish (unfinished ());
2532 setState (state_deactivated); // avoid recurstion through childDone
2533 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2534 if (e->active ())
2535 e->deactivate ();
2536 else
2537 e->message (MsgMediaPrefetch, MsgBool (0));
2538 if (need_finish)
2539 finish ();
2540 runtime->init ();
2541 Element::deactivate ();
2542 }
2543
reset()2544 KDE_NO_EXPORT void SMIL::GroupBase::reset () {
2545 Element::reset ();
2546 runtime->init ();
2547 }
2548
setJumpNode(NodePtr n)2549 KDE_NO_EXPORT void SMIL::GroupBase::setJumpNode (NodePtr n) {
2550 NodePtr child = n;
2551 if (state > state_init) {
2552 state = state_deferred;
2553 for (NodePtr c = firstChild (); c; c = c->nextSibling ())
2554 if (c->active ())
2555 c->reset ();
2556 for (Node *c = n->parentNode (); c; c = c->parentNode ()) {
2557 if (c == this || c->id == id_node_body)
2558 break;
2559 if (c->id >= id_node_first_group && c->id <= id_node_last_group)
2560 static_cast <SMIL::GroupBase *> (c)->jump_node = child;
2561 child = c;
2562 }
2563 }
2564 jump_node = child;
2565 state = state_activated;
2566 init ();
2567 for (NodePtr n = firstChild (); n; n = n->nextSibling ())
2568 if (n->role (RoleTiming))
2569 convertNode <Element> (n)->init ();
2570 runtime->startAndBeginNode (); // undefer through begin()
2571 }
2572
2573 //-----------------------------------------------------------------------------
2574
2575 // SMIL::Body was here
2576
2577 //-----------------------------------------------------------------------------
2578
begin()2579 KDE_NO_EXPORT void SMIL::Par::begin () {
2580 jump_node = 0L; // TODO: adjust timings
2581 setState (state_began);
2582 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2583 e->activate ();
2584 }
2585
reset()2586 KDE_NO_EXPORT void SMIL::Par::reset () {
2587 GroupBase::reset ();
2588 for (NodePtr e = firstChild (); e; e = e->nextSibling ())
2589 e->reset ();
2590 }
2591
childrenReady(Node * node)2592 static bool childrenReady (Node *node) {
2593 for (Node *n = node->firstChild (); n; n = n->nextSibling ())
2594 if (!n->role (RoleReady))
2595 return false;
2596 return true;
2597 }
2598
message(MessageType msg,void * content)2599 KDE_NO_EXPORT void SMIL::Par::message (MessageType msg, void *content) {
2600 switch (msg) {
2601
2602 case MsgChildReady:
2603 if (childrenReady (this)) {
2604 const int cur_state = state;
2605 if (state == state_deferred) {
2606 state = state_activated;
2607 runtime->start ();
2608 }
2609 if (cur_state == state_init && parentNode ())
2610 parentNode ()->message (MsgChildReady, this);
2611 }
2612 return;
2613
2614 case MsgChildFinished: {
2615 if (unfinished ()) {
2616 FreezeStateUpdater visitor;
2617 accept (&visitor);
2618 runtime->tryFinish ();
2619 }
2620 return;
2621 }
2622 default:
2623 break;
2624 }
2625 GroupBase::message (msg, content);
2626 }
2627
role(RoleType msg,void * content)2628 KDE_NO_EXPORT void *SMIL::Par::role (RoleType msg, void *content) {
2629 switch (msg) {
2630 case RoleReady:
2631 return MsgBool (childrenReady (this));
2632 default:
2633 break;
2634 }
2635 return GroupBase::role (msg, content);
2636 }
2637
2638
2639 //-----------------------------------------------------------------------------
2640
begin()2641 KDE_NO_EXPORT void SMIL::Seq::begin () {
2642 setState (state_began);
2643 if (jump_node) {
2644 starting_connection.disconnect ();
2645 trans_connection.disconnect ();
2646 for (NodePtr c = firstChild (); c; c = c->nextSibling ())
2647 if (c == jump_node) {
2648 jump_node = 0L;
2649 c->activate ();
2650 break;
2651 } else {
2652 c->state = state_activated; // TODO: ..
2653 if (c->isElementNode ())
2654 convertNode <Element> (c)->init ();
2655 c->state = state_finished; // TODO: ..
2656 Runtime *rt = (Runtime *) c->role (RoleTiming);
2657 if (rt)
2658 rt->timingstate = Runtime::timings_stopped; //TODO fill_hold
2659 }
2660 } else if (firstChild ()) {
2661 if (firstChild ()->nextSibling()) {
2662 GroupBaseInitVisitor visitor;
2663 firstChild ()->nextSibling ()->accept (&visitor);
2664 }
2665 starting_connection.connect (firstChild (), MsgEventStarted, this);
2666 firstChild ()->activate ();
2667 }
2668 }
2669
message(MessageType msg,void * content)2670 KDE_NO_EXPORT void SMIL::Seq::message (MessageType msg, void *content) {
2671 switch (msg) {
2672
2673 case MsgChildReady:
2674 if (firstChild () == (Node *) content) {
2675 if (state == state_deferred) {
2676 state = state_activated;
2677 runtime->start ();
2678 }
2679 if (state == state_init && parentNode ())
2680 parentNode ()->message (MsgChildReady, this);
2681 } else if (unfinished ()) {
2682 FreezeStateUpdater visitor;
2683 accept (&visitor);
2684 }
2685 return;
2686
2687 case MsgChildFinished: {
2688 if (unfinished ()) {
2689 Posting *post = (Posting *) content;
2690 if (state != state_deferred) {
2691 Node *next = post->source
2692 ? post->source->nextSibling ()
2693 : NULL;
2694 if (next) {
2695 if (next->nextSibling()) {
2696 GroupBaseInitVisitor visitor;
2697 next->nextSibling ()->accept (&visitor);
2698 }
2699 starting_connection.connect(next, MsgEventStarted,this);
2700 trans_connection.connect (
2701 next, MsgChildTransformedIn, this);
2702 next->activate ();
2703 } else {
2704 starting_connection.disconnect ();
2705 trans_connection.disconnect ();
2706 runtime->tryFinish ();
2707 }
2708 FreezeStateUpdater visitor;
2709 accept (&visitor);
2710 } else if (jump_node) {
2711 finish ();
2712 }
2713 }
2714 return;
2715 }
2716
2717 case MsgEventStarted: {
2718 Posting *event = static_cast <Posting *> (content);
2719 Node *source = event->source;
2720 if (source != this && source->previousSibling ()) {
2721 FreezeStateUpdater visitor;
2722 starting_connection.disconnect ();
2723 accept (&visitor);
2724 }
2725 break;
2726 }
2727
2728 case MsgChildTransformedIn: {
2729 Node *source = (Node *) content;
2730 if (source != this && source->previousSibling ()) {
2731 FreezeStateUpdater visitor;
2732 starting_connection.disconnect ();
2733 accept (&visitor);
2734 }
2735 break;
2736 }
2737
2738 default:
2739 break;
2740 }
2741 GroupBase::message (msg, content);
2742 }
2743
role(RoleType msg,void * content)2744 KDE_NO_EXPORT void *SMIL::Seq::role (RoleType msg, void *content) {
2745 switch (msg) {
2746 case RoleReady:
2747 return MsgBool (!firstChild () || firstChild ()->role (RoleReady));
2748 default:
2749 break;
2750 }
2751 return GroupBase::role (msg, content);
2752 }
2753
2754
2755 //-----------------------------------------------------------------------------
2756
childFromTag(const QString & tag)2757 KDE_NO_EXPORT Node *SMIL::Excl::childFromTag (const QString &tag) {
2758 if (tag == "priorityClass")
2759 return new PriorityClass (m_doc);
2760 return GroupBase::childFromTag (tag);
2761 }
2762
2763 namespace {
2764
2765 class KMPLAYER_NO_EXPORT ExclActivateVisitor : public Visitor {
2766 SMIL::Excl *excl;
2767 public:
ExclActivateVisitor(SMIL::Excl * ex)2768 ExclActivateVisitor (SMIL::Excl *ex) : excl (ex) {}
2769
2770 using Visitor::visit;
2771
visit(Node * n)2772 void visit (Node *n) {
2773 Node *s = n->nextSibling ();
2774 if (s)
2775 s->accept (this);
2776 }
visit(Element * elm)2777 void visit (Element *elm) {
2778 if (elm->role (RoleTiming)) {
2779 // make aboutToStart connection with Timing
2780 excl->started_event_list =
2781 new SMIL::Excl::ConnectionItem (excl->started_event_list);
2782 excl->started_event_list->link.connect (elm, MsgEventStarting, excl);
2783 elm->activate ();
2784 }
2785 visit (static_cast <Node *> (elm));
2786 }
visit(SMIL::PriorityClass * pc)2787 void visit (SMIL::PriorityClass *pc) {
2788 pc->init ();
2789 pc->state = Node::state_activated;
2790 Node *n = pc->firstChild ();
2791 if (n)
2792 n->accept (this);
2793 visit (static_cast <Node *> (pc));
2794 }
2795 };
2796
2797 class KMPLAYER_NO_EXPORT ExclPauseVisitor : public Visitor {
2798 bool pause;
2799 Node *paused_by;
2800 unsigned int cur_time;
2801
updatePauseStateEvent(Posting * event,int pause_time)2802 void updatePauseStateEvent (Posting *event, int pause_time) {
2803 if (event) {
2804 if (pause)
2805 paused_by->document ()->pausePosting (event);
2806 else
2807 paused_by->document ()->unpausePosting (event, (cur_time-pause_time)*10);
2808 }
2809 }
activeEvent(Runtime * r)2810 static Posting *activeEvent (Runtime *r) {
2811 Posting *event = NULL;
2812 if (r->begin_timer)
2813 event = r->begin_timer;
2814 else if (r->started_timer)
2815 event = r->started_timer;
2816 else if (r->duration_timer)
2817 event = r->duration_timer;
2818 else if (r->stopped_timer)
2819 event = r->stopped_timer;
2820 return event;
2821 }
2822
2823 public:
ExclPauseVisitor(bool p,Node * pb,unsigned int pt)2824 ExclPauseVisitor (bool p, Node *pb, unsigned int pt)
2825 : pause(p), paused_by (pb), cur_time (pt) {}
~ExclPauseVisitor()2826 ~ExclPauseVisitor () {
2827 paused_by->document ()->updateTimeout ();
2828 }
2829
2830 using Visitor::visit;
2831
visit(Node * node)2832 void visit (Node *node) {
2833 for (Node *c = node->firstChild (); c; c = c->nextSibling ())
2834 c->accept (this);
2835 }
visit(Element * elm)2836 void visit (Element *elm) {
2837 if (!elm->active ())
2838 return; // nothing to do
2839 Runtime *rt = (Runtime *) elm->role (RoleTiming);
2840 if (rt) {
2841 if (pause) {
2842 rt->paused_time = cur_time;
2843 rt->paused_by = paused_by;
2844 rt->unpaused_state = rt->timingstate;
2845 rt->timingstate = Runtime::timings_paused;
2846 } else {
2847 rt->paused_by = NULL;
2848 rt->timingstate = rt->unpaused_state;
2849 rt->start_time += cur_time;
2850 }
2851 updatePauseStateEvent (activeEvent (rt), rt->paused_time);
2852 }
2853 visit (static_cast <Node *> (elm));
2854 }
visit(SMIL::MediaType * mt)2855 void visit (SMIL::MediaType *mt) {
2856 if (mt->media_info && mt->media_info->media) {
2857 if (pause)
2858 mt->media_info->media->pause ();
2859 else
2860 mt->media_info->media->unpause ();
2861 Surface *s = mt->surface ();
2862 if (s)
2863 s->repaint ();
2864 }
2865
2866 Posting *event = NULL;
2867 if (mt->transition.trans_out_timer)
2868 event = mt->transition.trans_out_timer;
2869 updatePauseStateEvent (event, mt->runtime->paused_time);
2870
2871 visit (static_cast <Element *> (mt));
2872 }
visit(SMIL::AnimateBase * an)2873 void visit (SMIL::AnimateBase *an) {
2874 updatePauseStateEvent(an->anim_timer, an->runtime->paused_time);
2875 visit (static_cast <Element *> (an));
2876 }
visit(SMIL::Smil * s)2877 void visit (SMIL::Smil *s) {
2878 for (Node *c = s->firstChild (); c; c = c->nextSibling ())
2879 if (SMIL::id_node_body == c->id)
2880 c->accept (this);
2881 }
2882 };
2883
2884 }
2885
clearList(SMIL::Excl::ConnectionItem ** pitem)2886 static void clearList (SMIL::Excl::ConnectionItem **pitem) {
2887 SMIL::Excl::ConnectionItem *item = *pitem;
2888 while (item) {
2889 SMIL::Excl::ConnectionItem *tmp = item;
2890 item = item->next;
2891 delete tmp;
2892 }
2893 *pitem = NULL;
2894 }
2895
Excl(NodePtr & d)2896 KDE_NO_CDTOR_EXPORT SMIL::Excl::Excl (NodePtr & d)
2897 : GroupBase (d, id_node_excl), started_event_list (NULL) {}
2898
~Excl()2899 KDE_NO_CDTOR_EXPORT SMIL::Excl::~Excl () {
2900 clearList (&started_event_list);
2901 }
2902
begin()2903 KDE_NO_EXPORT void SMIL::Excl::begin () {
2904 Node *n = firstChild ();
2905 if (n) {
2906 ExclActivateVisitor visitor (this);
2907 n->accept (&visitor);
2908 }
2909 }
2910
deactivate()2911 KDE_NO_EXPORT void SMIL::Excl::deactivate () {
2912 clearList (&started_event_list);
2913 priority_queue.clear ();
2914 stopped_connection.disconnect ();
2915 GroupBase::deactivate ();
2916 }
2917
message(MessageType msg,void * content)2918 KDE_NO_EXPORT void SMIL::Excl::message (MessageType msg, void *content) {
2919 switch (msg) {
2920 case MsgEventStarting: {
2921 Node *source = (Node *) content;
2922 NodePtr n = cur_node;
2923 if (source == n.ptr ())
2924 return; // eg. repeating
2925 cur_node = source;
2926 stopped_connection.connect (cur_node, MsgEventStopped, this);
2927 if (n) {
2928 if (SMIL::id_node_priorityclass == cur_node->parentNode ()->id) {
2929 switch (static_cast <SMIL::PriorityClass *>
2930 (cur_node->parentNode ())->peers) {
2931 case PriorityClass::PeersPause: {
2932 ExclPauseVisitor visitor (
2933 true, this, document ()->last_event_time/10);
2934 n->accept (&visitor);
2935 priority_queue.insertBefore (
2936 new NodeRefItem (n), priority_queue.first ());
2937 return;
2938 }
2939 default:
2940 break; //TODO
2941 }
2942 }
2943 ((Runtime*)n->role (RoleTiming))->doFinish ();
2944 }
2945 return;
2946 }
2947 case MsgChildFinished: {
2948 Posting *event = static_cast <Posting *> (content);
2949 FreezeStateUpdater visitor;
2950 accept (&visitor);
2951 if (event->source == cur_node) {
2952 Runtime* rt = (Runtime*)cur_node->role (RoleTiming);
2953 if (rt && rt->timingstate == Runtime::timings_stopped) {
2954 cur_node = NULL;
2955 stopped_connection.disconnect ();
2956 }
2957 runtime->tryFinish ();
2958 }
2959 return;
2960 }
2961 case MsgEventStopped: {
2962 Posting *event = static_cast <Posting *> (content);
2963 if (event->source == cur_node) {
2964
2965 NodeRefItemPtr ref = priority_queue.first ();
2966 while (ref && (!ref->data || !ref->data->active ())) {
2967 // should not happen, but consider a backend crash or so
2968 priority_queue.remove (ref);
2969 ref = priority_queue.first ();
2970 }
2971 if (ref) {
2972 cur_node = ref->data;
2973 priority_queue.remove (ref);
2974 stopped_connection.connect (cur_node, MsgEventStopped, this);
2975 ExclPauseVisitor visitor (false, this, document()->last_event_time/10);
2976 cur_node->accept (&visitor);
2977 // else TODO
2978 }
2979 }
2980 break;
2981 }
2982 default:
2983 break;
2984 }
2985 GroupBase::message (msg, content);
2986 }
2987
2988 //-----------------------------------------------------------------------------
2989
childFromTag(const QString & tag)2990 KDE_NO_EXPORT Node *SMIL::PriorityClass::childFromTag (const QString &tag) {
2991 Element * elm = fromScheduleGroup (m_doc, tag);
2992 if (!elm) elm = fromMediaContentGroup (m_doc, tag);
2993 if (!elm) elm = fromContentControlGroup (m_doc, tag);
2994 if (!elm) elm = fromAnimateGroup (m_doc, tag);
2995 if (elm)
2996 return elm;
2997 return NULL;
2998 }
2999
3000 KDE_NO_EXPORT void
parseParam(const TrieString & name,const QString & val)3001 SMIL::PriorityClass::parseParam (const TrieString &name, const QString &val) {
3002 if (name == "peers") {
3003 if (val == "pause")
3004 peers = PeersPause;
3005 else if (val == "defer")
3006 peers = PeersDefer;
3007 else if (val == "never")
3008 peers = PeersNever;
3009 else
3010 peers = PeersStop;
3011 } else if (name == "higher") {
3012 if (val == "stop")
3013 higher = HigherStop;
3014 else
3015 higher = HigherPause;
3016 } else if (name == "lower") {
3017 if (val == "never")
3018 lower = LowerNever;
3019 else
3020 lower = LowerDefer;
3021 } else if (name == "pauseDisplay") {
3022 if (val == "disable")
3023 pause_display = PauseDisplayDisable;
3024 else if (val == "hide")
3025 pause_display = PauseDisplayHide;
3026 else
3027 pause_display = PauseDisplayShow;
3028 }
3029 }
3030
init()3031 KDE_NO_EXPORT void SMIL::PriorityClass::init () {
3032 peers = PeersStop;
3033 higher = HigherPause;
3034 lower = LowerDefer;
3035 pause_display = PauseDisplayShow;
3036 Element::init ();
3037 }
3038
message(MessageType msg,void * data)3039 KDE_NO_EXPORT void SMIL::PriorityClass::message (MessageType msg, void *data) {
3040 if (MsgChildFinished == msg)
3041 // do nothing
3042 return;
3043 Element::message (msg, data);
3044 }
3045
3046 //-----------------------------------------------------------------------------
3047
init()3048 KDE_NO_EXPORT void SMIL::Switch::init () {
3049 Node *n = chosen_one.ptr ();
3050 chosen_one = NULL;
3051 if (n && n->active ())
3052 n->deactivate ();
3053 GroupBase::init ();
3054 }
3055
chosenOne()3056 KDE_NO_EXPORT Node *SMIL::Switch::chosenOne () {
3057 if (!chosen_one && firstChild ()) {
3058 PlayListNotify * n = document()->notify_listener;
3059 int pref = 0, max = 0x7fffffff, currate = 0;
3060 if (n)
3061 n->bitRates (pref, max);
3062 if (firstChild ()) {
3063 Node *fallback = NULL;
3064 for (Node *e = firstChild (); e; e = e->nextSibling ())
3065 if (e->isElementNode ()) {
3066 Element *elm = static_cast <Element *> (e);
3067 Runtime *rt = (Runtime *) e->role (RoleTiming);
3068 if (rt) {
3069 if (rt->state () < Runtime::TimingsInitialized)
3070 elm->init ();
3071 if (!disabledByExpr (rt)) {
3072 QString lang = elm->getAttribute ("systemLanguage");
3073 if (!lang.isEmpty ()) {
3074 lang = lang.replace (QChar ('-'), QChar ('_'));
3075 char *clang = getenv ("LANG");
3076 if (!clang) {
3077 if (!fallback)
3078 fallback = e;
3079 } else if (QString (clang).toLower ().startsWith (lang)) {
3080 chosen_one = e;
3081 } else if (!fallback) {
3082 fallback = e->nextSibling ();
3083 }
3084 }
3085 if (e->id == id_node_ref) {
3086 SMIL::MediaType * mt = static_cast<SMIL::MediaType*>(e);
3087 if (!chosen_one) {
3088 chosen_one = e;
3089 currate = mt->bitrate;
3090 } else if (int (mt->bitrate) <= max) {
3091 int delta1 = pref > currate ? pref-currate : currate-pref;
3092 int delta2 = pref > int (mt->bitrate) ? pref-mt->bitrate : mt->bitrate-pref;
3093 if (delta2 < delta1) {
3094 chosen_one = e;
3095 currate = mt->bitrate;
3096 }
3097 }
3098 } else if (!fallback)
3099 fallback = e;
3100 }
3101 }
3102 }
3103 if (!chosen_one)
3104 chosen_one = (fallback ? fallback : firstChild ());
3105 }
3106 }
3107 return chosen_one.ptr ();
3108 }
3109
begin()3110 KDE_NO_EXPORT void SMIL::Switch::begin () {
3111 Node *n = chosenOne ();
3112 if (n)
3113 n->activate ();
3114 else
3115 runtime->tryFinish ();
3116 }
3117
deactivate()3118 KDE_NO_EXPORT void SMIL::Switch::deactivate () {
3119 chosen_one = NULL;
3120 GroupBase::deactivate ();
3121 }
3122
reset()3123 KDE_NO_EXPORT void SMIL::Switch::reset () {
3124 GroupBase::reset ();
3125 for (NodePtr e = firstChild (); e; e = e->nextSibling ()) {
3126 if (e->state != state_init)
3127 e->reset ();
3128 }
3129 }
3130
message(MessageType msg,void * content)3131 KDE_NO_EXPORT void SMIL::Switch::message (MessageType msg, void *content) {
3132 switch (msg) {
3133 case MsgChildFinished: {
3134 Posting *post = (Posting *) content;
3135 if (unfinished () && post->source == chosen_one) {
3136 runtime->tryFinish ();
3137 FreezeStateUpdater visitor;
3138 accept (&visitor);
3139 }
3140 return;
3141 }
3142 case MsgStateRewind:
3143 chosen_one = NULL;
3144 break;
3145 default:
3146 break;
3147 }
3148 GroupBase::message (msg, content);
3149 }
3150
3151 //-----------------------------------------------------------------------------
3152
LinkingBase(NodePtr & d,short id)3153 KDE_NO_CDTOR_EXPORT SMIL::LinkingBase::LinkingBase (NodePtr & d, short id)
3154 : Element(d, id), show (show_replace) {}
3155
deactivate()3156 KDE_NO_EXPORT void SMIL::LinkingBase::deactivate () {
3157 mediatype_attach.disconnect ();
3158 Element::deactivate ();
3159 }
3160
3161 KDE_NO_EXPORT
parseParam(const TrieString & para,const QString & val)3162 void SMIL::LinkingBase::parseParam(const TrieString ¶, const QString &val) {
3163 if (para == Ids::attr_href) {
3164 href = val;
3165 } else if (para == Ids::attr_target) {
3166 target = val;
3167 }
3168 }
3169
3170 //-----------------------------------------------------------------------------
3171
Anchor(NodePtr & d)3172 KDE_NO_CDTOR_EXPORT SMIL::Anchor::Anchor (NodePtr & d)
3173 : LinkingBase (d, id_node_anchor) {}
3174
activate()3175 KDE_NO_EXPORT void SMIL::Anchor::activate () {
3176 init ();
3177 for (Node *c = firstChild(); c; c = c->nextSibling ())
3178 if (nodeMessageReceivers (c, MsgEventClicked)) {
3179 mediatype_attach.connect (c, MsgSurfaceAttach, this);
3180 break;
3181 }
3182 Element::activate ();
3183 }
3184
message(MessageType msg,void * content)3185 KDE_NO_EXPORT void SMIL::Anchor::message (MessageType msg, void *content) {
3186 switch (msg) {
3187
3188 case MsgChildReady:
3189 if (parentNode ())
3190 parentNode ()->message (MsgChildReady, this);
3191 return;
3192
3193 case MsgChildFinished: {
3194 Posting *post = (Posting *) content;
3195 if (unfinished ()) {
3196 if (post->source->nextSibling ())
3197 post->source->nextSibling ()->activate ();
3198 else
3199 finish ();
3200 }
3201 return;
3202 }
3203
3204 default:
3205 break;
3206 }
3207 LinkingBase::message (msg, content);
3208 }
3209
childFromTag(const QString & tag)3210 Node *SMIL::Anchor::childFromTag (const QString & tag) {
3211 return fromMediaContentGroup (m_doc, tag);
3212 }
3213
role(RoleType msg,void * content)3214 KDE_NO_EXPORT void *SMIL::Anchor::role (RoleType msg, void *content) {
3215 switch (msg) {
3216 case RoleReady:
3217 return MsgBool (childrenReady (this));
3218 default:
3219 break;
3220 }
3221 return LinkingBase::role (msg, content);
3222 }
3223
3224
3225 //-----------------------------------------------------------------------------
3226
Area(NodePtr & d,const QString & t)3227 KDE_NO_CDTOR_EXPORT SMIL::Area::Area (NodePtr & d, const QString & t)
3228 : LinkingBase (d, id_node_area), coords (0L), nr_coords (0), tag (t.toUtf8()) {}
3229
~Area()3230 KDE_NO_CDTOR_EXPORT SMIL::Area::~Area () {
3231 delete [] coords;
3232 }
3233
activate()3234 KDE_NO_EXPORT void SMIL::Area::activate () {
3235 init ();
3236 if (parentNode () &&
3237 parentNode ()->id >= id_node_first_mediatype &&
3238 parentNode ()->id <= id_node_last_mediatype) {
3239 mediatype_attach.connect (parentNode (), MsgSurfaceAttach, this);
3240 }
3241 Element::activate ();
3242 }
3243
3244 KDE_NO_EXPORT
parseParam(const TrieString & para,const QString & val)3245 void SMIL::Area::parseParam (const TrieString & para, const QString & val) {
3246 if (para == "coords") {
3247 delete [] coords;
3248 QStringList clist = val.split (QChar (','));
3249 nr_coords = clist.count ();
3250 coords = new SizeType [nr_coords];
3251 for (int i = 0; i < nr_coords; ++i)
3252 coords[i] = clist[i];
3253 } else
3254 LinkingBase::parseParam (para, val);
3255 }
3256
role(RoleType msg,void * content)3257 KDE_NO_EXPORT void *SMIL::Area::role (RoleType msg, void *content) {
3258 ConnectionList *l = mouse_listeners.receivers ((MessageType) (long) content);
3259 if (l)
3260 return l;
3261 return Element::role (msg, content);
3262 }
3263
3264 //-----------------------------------------------------------------------------
3265
MediaType(NodePtr & d,const QByteArray & t,short id)3266 KDE_NO_CDTOR_EXPORT SMIL::MediaType::MediaType (NodePtr &d, const QByteArray &t, short id)
3267 : Mrl (d, id),
3268 runtime (new Runtime (this)),
3269 m_type (t),
3270 pan_zoom (NULL),
3271 bitrate (0),
3272 sensitivity (sens_opaque) {
3273 view_mode = Mrl::WindowMode;
3274 }
3275
~MediaType()3276 KDE_NO_CDTOR_EXPORT SMIL::MediaType::~MediaType () {
3277 delete runtime;
3278 delete pan_zoom;
3279 }
3280
childFromTag(const QString & tag)3281 KDE_NO_EXPORT Node *SMIL::MediaType::childFromTag (const QString & tag) {
3282 Element * elm = fromContentControlGroup (m_doc, tag);
3283 if (!elm) elm = fromParamGroup (m_doc, tag);
3284 if (!elm) elm = fromAnimateGroup (m_doc, tag);
3285 if (elm)
3286 return elm;
3287 return NULL;
3288 }
3289
findExternalTree(Mrl * mrl)3290 static NodePtr findExternalTree (Mrl *mrl) {
3291 for (Node *c = mrl->firstChild (); c; c = c->nextSibling ()) {
3292 Mrl * m = c->mrl ();
3293 if (m && (m->opener.ptr () == mrl ||
3294 m->id == SMIL::id_node_smil ||
3295 m->id == RP::id_node_imfl))
3296 return c;
3297 }
3298 return 0L;
3299 }
3300
closed()3301 KDE_NO_EXPORT void SMIL::MediaType::closed () {
3302 external_tree = findExternalTree (this);
3303 Mrl *mrl = external_tree ? external_tree->mrl () : NULL;
3304 if (mrl)
3305 size = mrl->size;
3306 title = getAttribute (Ids::attr_title);
3307 Mrl::closed ();
3308 }
3309
prefetch()3310 KDE_NO_EXPORT void SMIL::MediaType::prefetch () {
3311 }
3312
3313 KDE_NO_EXPORT
parseParam(const TrieString & para,const QString & val)3314 void SMIL::MediaType::parseParam (const TrieString ¶, const QString & val) {
3315 if (para == Ids::attr_src) {
3316 if (src != val) {
3317 src = val;
3318 if (external_tree)
3319 removeChild (external_tree);
3320 delete media_info;
3321 media_info = NULL;
3322 if (!val.isEmpty () && runtimeBegan (runtime))
3323 prefetch ();
3324 if (state == state_began && resolved)
3325 clipStart ();
3326 }
3327 } else if (para == Ids::attr_fit) {
3328 fit = parseFit (val.toAscii ().constData ());
3329 if (fit != effective_fit)
3330 message (MsgSurfaceBoundsUpdate);
3331 } else if (para == Ids::attr_type) {
3332 mimetype = val;
3333 } else if (para == "panZoom") {
3334 QStringList coords = val.split (QChar (','));
3335 if (coords.size () < 4) {
3336 kWarning () << "panZoom less then four nubmers";
3337 return;
3338 }
3339 if (!pan_zoom)
3340 pan_zoom = new CalculatedSizer;
3341 pan_zoom->left = coords[0];
3342 pan_zoom->top = coords[1];
3343 pan_zoom->width = coords[2];
3344 pan_zoom->height = coords[3];
3345 } else if (parseBackgroundParam (background_color, para, val) ||
3346 parseMediaOpacityParam (media_opacity, para, val)) {
3347 } else if (para == "system-bitrate") {
3348 bitrate = val.toInt ();
3349 } else if (parseTransitionParam (this, transition, runtime, para, val)) {
3350 } else if (para == "sensitivity") {
3351 if (val == "transparent")
3352 sensitivity = sens_transparent;
3353 //else if (val == "percentage") // TODO
3354 // sensitivity = sens_percentage;
3355 else
3356 sensitivity = sens_opaque;
3357 } else if (sizes.setSizeParam (para, val)) {
3358 message (MsgSurfaceBoundsUpdate);
3359 } else if (!runtime->parseParam (para, val)) {
3360 Mrl::parseParam (para, val);
3361 }
3362 if (sub_surface) {
3363 sub_surface->markDirty ();
3364 sub_surface->setBackgroundColor (background_color.color);
3365 sub_surface->repaint ();
3366 }
3367 }
3368
init()3369 KDE_NO_EXPORT void SMIL::MediaType::init () {
3370 if (Runtime::TimingsInitialized > runtime->timingstate) {
3371 fit = fit_default;
3372 effective_fit = fit_default;
3373 background_color.init ();
3374 media_opacity.init ();
3375 transition.init ();
3376 QString pg = getAttribute ("paramGroup");
3377 if (!pg.isEmpty ()) {
3378 Node *head = findHeadNode (SMIL::Smil::findSmilNode(this));
3379 if (head) {
3380 Expression *expr = evaluateExpr(QString("/paramGroup[@id='" + pg + "']/param").toUtf8());
3381 if (expr) {
3382 expr->setRoot (head);
3383 Expression::iterator it, e = expr->end();
3384 for (it = expr->begin(); it != e; ++it) {
3385 if (it->node->isElementNode()) {
3386 Element *e = static_cast <Element*>(it->node);
3387 QString n = e->getAttribute (Ids::attr_name);
3388 if (!n.isEmpty ())
3389 parseParam (n, e->getAttribute (Ids::attr_value));
3390 }
3391 }
3392 delete expr;
3393 }
3394 }
3395 }
3396 Mrl::init (); // sets all attributes
3397 for (NodePtr c = firstChild (); c; c = c->nextSibling ())
3398 if (SMIL::id_node_param == c->id)
3399 c->activate (); // activate param children
3400 runtime->initialize ();
3401 }
3402 }
3403
activate()3404 KDE_NO_EXPORT void SMIL::MediaType::activate () {
3405 init (); // sets all attributes
3406 setState (state_activated);
3407 for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
3408 QString v = a->value ();
3409 int p = v.indexOf ('{');
3410 if (p > -1) {
3411 int q = v.indexOf ('}', p + 1);
3412 if (q > -1)
3413 parseParam (a->name (), applySubstitution (this, v, p, q));
3414 }
3415 }
3416 if (!runtime->started ())
3417 runtime->start ();
3418 }
3419
deactivate()3420 KDE_NO_EXPORT void SMIL::MediaType::deactivate () {
3421 region_attach.disconnect ();
3422 if (region_node)
3423 convertNode <SMIL::RegionBase> (region_node)->repaint ();
3424 transition.finish (this);
3425 runtime->init ();
3426 Mrl::deactivate ();
3427 (void) surface ();
3428 region_node = 0L;
3429 postpone_lock = 0L;
3430 }
3431
defer()3432 KDE_NO_EXPORT void SMIL::MediaType::defer () {
3433 if (media_info) {
3434 //media_info->pause ();
3435 bool running = unfinished ();
3436 setState (state_deferred);
3437 if (running)
3438 postpone_lock = document ()->postpone ();
3439 }
3440 }
3441
undefer()3442 KDE_NO_EXPORT void SMIL::MediaType::undefer () {
3443 if (runtime->started ()) {
3444 setState (state_began);
3445 if (media_info && media_info->media)
3446 media_info->media->unpause ();
3447 Surface *s = surface ();
3448 if (s)
3449 s->repaint ();
3450 } else {
3451 setState (state_activated);
3452 }
3453 postpone_lock = 0L;
3454 }
3455
begin()3456 KDE_NO_EXPORT void SMIL::MediaType::begin () {
3457 if (!src.isEmpty () && !media_info)
3458 prefetch ();
3459 if (media_info && media_info->downloading ()) {
3460 postpone_lock = document ()->postpone ();
3461 state = state_began;
3462 return; // wait for MsgMediaReady
3463 }
3464
3465 SMIL::RegionBase *r = findRegion (this, param (Ids::attr_region));
3466 transition.cancelTimer (this); // eg transOut and we're repeating
3467 for (NodePtr c = firstChild (); c; c = c->nextSibling ())
3468 if (SMIL::id_node_param != c->id && c != external_tree)
3469 c->activate (); // activate set/animate.. children
3470 if (r) {
3471 region_node = r;
3472 region_attach.connect (r, MsgSurfaceAttach, this);
3473 r->repaint ();
3474 clipStart ();
3475 transition.begin (this, runtime);
3476 } else {
3477 kWarning () << nodeName() << "::begin " << src << " region '" <<
3478 param (Ids::attr_region) << "' not found" << endl;
3479 }
3480 Element::begin ();
3481 }
3482
clipStart()3483 KDE_NO_EXPORT void SMIL::MediaType::clipStart () {
3484 if (region_node && region_node->role (RoleDisplay)) {
3485 if (external_tree)
3486 external_tree->activate ();
3487 else if (media_info && media_info->media)
3488 media_info->media->play ();
3489 }
3490 }
3491
clipStop()3492 KDE_NO_EXPORT void SMIL::MediaType::clipStop () {
3493 if (runtime->timingstate == Runtime::timings_stopped) {
3494 region_attach.disconnect ();
3495 if (media_info && media_info->media)
3496 media_info->media->stop ();
3497 if (external_tree && external_tree->active ())
3498 external_tree->deactivate ();
3499 }
3500 if (sub_surface)
3501 sub_surface->repaint ();
3502 document_postponed.disconnect ();
3503 }
3504
finish()3505 KDE_NO_EXPORT void SMIL::MediaType::finish () {
3506 transition.transition_updater.disconnect ();
3507 if (media_info && media_info->media)
3508 media_info->media->pause ();
3509 postpone_lock = 0L;
3510
3511 Surface *s = surface ();
3512 if (s)
3513 s->repaint ();
3514 runtime->finish ();
3515 }
3516
reset()3517 KDE_NO_EXPORT void SMIL::MediaType::reset () {
3518 Mrl::reset ();
3519 runtime->init ();
3520 }
3521
calculateBounds()3522 KDE_NO_EXPORT SRect SMIL::MediaType::calculateBounds () {
3523 SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
3524 if (rb && rb->role (RoleDisplay)) {
3525 SRect rr = rb->region_surface->bounds;
3526 Single x, y, w = size.width, h = size.height;
3527 sizes.calcSizes (this, &rb->sizes, rr.width(), rr.height(), x, y, w, h);
3528 if (fit_default != fit)
3529 effective_fit = fit;
3530 ImageMedia *im;
3531 switch (effective_fit) {
3532 case fit_scroll:
3533 case fit_default:
3534 case fit_hidden:
3535 if (media_info &&
3536 (MediaManager::AudioVideo == media_info->type ||
3537 (MediaManager::Image == media_info->type &&
3538 (im = static_cast <ImageMedia *>(media_info->media)) &&
3539 !im->isEmpty () &&
3540 im->cached_img->flags & ImageData::ImageScalable)))
3541 effective_fit = fit_meet;
3542 break;
3543 default:
3544 break;
3545 }
3546
3547 if (!size.isEmpty () && w > 0 && h > 0)
3548 switch (effective_fit) {
3549 case fit_meet: {
3550 float iasp = 1.0 * size.width / size.height;
3551 float rasp = 1.0 * w / h;
3552 if (iasp > rasp)
3553 h = size.height * w / size.width;
3554 else
3555 w = size.width * h / size.height;
3556 break;
3557 }
3558 case fit_scroll:
3559 case fit_default:
3560 case fit_hidden:
3561 w = size.width;
3562 h = size.height;
3563 break;
3564 case fit_slice: {
3565 float iasp = 1.0 * size.width / size.height;
3566 float rasp = 1.0 * w / h;
3567 if (iasp > rasp)
3568 w = size.width * h / size.height;
3569 else
3570 h = size.height * w / size.width;
3571 break;
3572 }
3573 default: {} // fit_fill
3574 }
3575 return SRect (x, y, w, h);
3576 }
3577 return SRect ();
3578 }
3579
message(MessageType msg,void * content)3580 void SMIL::MediaType::message (MessageType msg, void *content) {
3581 switch (msg) {
3582
3583 case MsgEventPostponed: {
3584 PostponedEvent *pe = static_cast <PostponedEvent *> (content);
3585 if (media_info) {
3586 if (pe->is_postponed) {
3587 if (unfinished ()) {
3588 setState (state_deferred);
3589 if (media_info->media)
3590 media_info->media->pause ();
3591 }
3592 } else if (state == Node::state_deferred) {
3593 setState (state_began);
3594 if (media_info->media)
3595 media_info->media->unpause ();
3596 }
3597 }
3598 return;
3599 }
3600
3601 case MsgSurfaceBoundsUpdate:
3602 if (sub_surface)
3603 sub_surface->resize (calculateBounds (), !!content);
3604 return;
3605
3606 case MsgStateFreeze:
3607 clipStop ();
3608 return;
3609
3610 case MsgChildFinished: {
3611 Posting *post = (Posting *) content;
3612 if (post->source->mrl () &&
3613 post->source->mrl ()->opener.ptr () == this) {
3614 post->source->deactivate (); // should only if fill not is freeze or hold
3615 } else if (active ()) {
3616 if (runtime->state () < Runtime::timings_stopped) {
3617 if (runtime->started ())
3618 runtime->tryFinish (); // what about repeat_count ..
3619 return; // still running, wait for runtime to finish
3620 }
3621 }
3622 if (active ())
3623 finish ();
3624 return;
3625 }
3626
3627 case MsgStateRewind:
3628 if (external_tree) {
3629 State old = state;
3630 state = state_deactivated;
3631 external_tree->reset ();
3632 state = old;
3633 }
3634 return;
3635
3636 case MsgMediaPrefetch:
3637 if (content) {
3638 init ();
3639 if (!src.isEmpty () && !media_info)
3640 prefetch ();
3641 } else if (media_info) {
3642 delete media_info;
3643 media_info = NULL;
3644 }
3645 return;
3646
3647 case MsgMediaReady: {
3648 resolved = true;
3649 Mrl *mrl = external_tree ? external_tree->mrl () : NULL;
3650 if (mrl)
3651 size = mrl->size;
3652 postpone_lock = 0L;
3653 message (MsgSurfaceBoundsUpdate, (void *) true);
3654 if (state == state_began) {
3655 begin ();
3656 runtime->tryFinish ();
3657 } else if (state < state_began && parentNode ()) {
3658 parentNode ()->message (MsgChildReady, this);
3659 }
3660 return;
3661 }
3662
3663 case MsgMediaFinished:
3664 if (state_deferred == state && postpone_lock)
3665 state = state_began;
3666 if (unfinished ()) {
3667 if (runtime->durTime ().durval == Runtime::DurMedia)
3668 runtime->durTime ().durval = Runtime::DurTimer;
3669 if (media_info) {
3670 delete media_info;
3671 media_info = NULL;
3672 }
3673 postpone_lock = 0L;
3674 runtime->tryFinish ();
3675 }
3676 return;
3677
3678 default:
3679 break;
3680 }
3681 if (!transition.handleMessage (this, runtime, surface (), msg, content)) {
3682 if ((int) msg >= (int) Runtime::DurLastDuration)
3683 Mrl::message (msg, content);
3684 else
3685 runtime->message (msg, content);
3686 }
3687 }
3688
role(RoleType msg,void * content)3689 void *SMIL::MediaType::role (RoleType msg, void *content) {
3690 switch (msg) {
3691
3692 case RoleReady:
3693 return MsgBool (!media_info || !media_info->downloading ());
3694
3695 case RoleTiming:
3696 return runtime;
3697
3698 case RoleDisplay:
3699 return surface ();
3700
3701 case RoleSizer:
3702 return &sizes;
3703
3704 case RoleChildDisplay: {
3705 Surface *s = NULL;
3706 Mrl *mrl = (Mrl *) content;
3707 if (mrl) {
3708 size = mrl->size;
3709 message (MsgSurfaceBoundsUpdate);
3710 s = surface ();
3711 }
3712 return s;
3713 }
3714
3715 case RolePlaylist:
3716 return NULL;
3717
3718 case RoleReceivers: {
3719 MessageType m = (MessageType) (long) content;
3720 ConnectionList *l = mouse_listeners.receivers (m);
3721 if (l)
3722 return l;
3723 if (MsgSurfaceAttach == m)
3724 return &m_MediaAttached;
3725 if (MsgChildTransformedIn == m)
3726 return &transition.m_TransformedIn;
3727 } // fall through
3728
3729 default:
3730 break;
3731 }
3732 void *response = runtime->role (msg, content);
3733 if (response == MsgUnhandled)
3734 return Mrl::role (msg, content);
3735 return response;
3736 }
3737
3738
surface()3739 Surface *SMIL::MediaType::surface () {
3740 if (!runtime->active ()) {
3741 if (sub_surface)
3742 sub_surface->remove ();
3743 sub_surface = NULL;
3744 } else if (!sub_surface && region_node) {
3745 Surface *rs = (Surface *) region_node->role (RoleDisplay);
3746 if (rs) {
3747 sub_surface = rs->createSurface (this, SRect ());
3748 sub_surface->setBackgroundColor (background_color.color);
3749 message (MsgSurfaceBoundsUpdate);
3750 }
3751 }
3752 return sub_surface.ptr ();
3753 }
3754
3755 //-----------------------------------------------------------------------------
3756
3757 namespace {
3758 class SvgElement : public Element {
3759 QByteArray tag;
3760 NodePtrW image;
3761
3762 public:
SvgElement(NodePtr & doc,Node * img,const QByteArray & t,short id=0)3763 SvgElement (NodePtr &doc, Node *img, const QByteArray &t, short id=0)
3764 : Element (doc, id), tag (t), image (img) {}
3765
parseParam(const TrieString & name,const QString & val)3766 void parseParam (const TrieString &name, const QString &val) {
3767 setAttribute (name, val);
3768 Mrl *mrl = image ? image->mrl () : NULL;
3769 if (mrl && mrl->media_info &&
3770 MediaManager::Image == mrl->media_info->type) {
3771 ImageMedia *im=static_cast<ImageMedia*>(mrl->media_info->media);
3772 if (im)
3773 im->updateRender ();
3774 }
3775 }
3776
childFromTag(const QString & tag)3777 Node *childFromTag (const QString & tag) {
3778 return new SvgElement (m_doc, image.ptr (), tag.toLatin1());
3779 }
3780
nodeName() const3781 const char *nodeName () const {
3782 return tag.constData ();
3783 }
3784 };
3785 }
3786
3787 KDE_NO_CDTOR_EXPORT
RefMediaType(NodePtr & d,const QByteArray & t)3788 SMIL::RefMediaType::RefMediaType (NodePtr &d, const QByteArray &t)
3789 : SMIL::MediaType (d, t, id_node_ref) {}
3790
childFromTag(const QString & tag)3791 KDE_NO_EXPORT Node *SMIL::RefMediaType::childFromTag (const QString & tag) {
3792 QByteArray ba = tag.toLatin1 ();
3793 const char *taglatin = ba.constData ();
3794 if (!strcmp (taglatin, "imfl"))
3795 return new RP::Imfl (m_doc);
3796 else if (!strcmp (taglatin, "svg"))
3797 return new SvgElement (m_doc, this, ba, id_node_svg);
3798 Node *n = fromXMLDocumentTag (m_doc, tag);
3799 if (n)
3800 return n;
3801 return SMIL::MediaType::childFromTag (tag);
3802 }
3803
prefetch()3804 KDE_NO_EXPORT void SMIL::RefMediaType::prefetch () {
3805 if (!src.isEmpty ()) {
3806 Node *n = findChildWithId (this, id_node_svg);
3807 if (n)
3808 removeChild (n);
3809 if (!media_info)
3810 media_info = new MediaInfo (this, MediaManager::Any);
3811 resolved = media_info->wget (absolutePath ());
3812 }
3813 }
3814
activate()3815 KDE_NO_EXPORT void SMIL::RefMediaType::activate () {
3816 MediaType::activate ();
3817
3818 if (src.isEmpty () && (!media_info || !media_info->media)) {
3819 Node *n = findChildWithId (this, id_node_svg);
3820 if (n) {
3821 if (!media_info)
3822 media_info = new MediaInfo (this, MediaManager::Image);
3823 media_info->media = new ImageMedia (this);
3824 message (MsgMediaReady);
3825 }
3826 }
3827 }
3828
clipStart()3829 KDE_NO_EXPORT void SMIL::RefMediaType::clipStart () {
3830 if (media_info && media_info->media &&
3831 media_info->media->type () != MediaManager::Image &&
3832 region_node && !external_tree && !src.isEmpty()) {
3833 repeat = runtime->repeat_count == Runtime::DurIndefinite
3834 ? 9998 : runtime->repeat_count;
3835 runtime->repeat_count = 1;
3836 document_postponed.connect (document(), MsgEventPostponed, this);
3837 }
3838 MediaType::clipStart ();
3839 }
3840
finish()3841 KDE_NO_EXPORT void SMIL::RefMediaType::finish () {
3842 if (media_info && media_info->media &&
3843 media_info->media->type () != MediaManager::Image &&
3844 runtime->durTime ().durval == Runtime::DurMedia)
3845 runtime->durTime ().durval = Runtime::DurTimer;//reset to make this finish
3846 MediaType::finish ();
3847 }
3848
begin()3849 KDE_NO_EXPORT void SMIL::RefMediaType::begin () {
3850 MediaType::begin ();
3851 if (media_info && media_info->media &&
3852 media_info->media->type () != MediaManager::Image &&
3853 0 == runtime->durTime ().offset &&
3854 Runtime::DurMedia == runtime->endTime ().durval)
3855 runtime->durTime ().durval = Runtime::DurMedia; // duration of clip
3856 }
3857
accept(Visitor * v)3858 KDE_NO_EXPORT void SMIL::RefMediaType::accept (Visitor * v) {
3859 v->visit (this);
3860 }
3861
message(MessageType msg,void * content)3862 void SMIL::RefMediaType::message (MessageType msg, void *content) {
3863 if (media_info &&
3864 media_info->media &&
3865 media_info->media->type () == MediaManager::Image) {
3866 switch (msg) {
3867
3868 case MsgMediaUpdated: {
3869 Surface *s = surface ();
3870 if (s) {
3871 s->markDirty ();
3872 s->repaint ();
3873 }
3874 if (state >= state_finished)
3875 clipStop ();
3876 return;
3877 }
3878
3879 case MsgChildFinished:
3880 if (id_node_svg == ((Posting *) content)->source->id)
3881 return;
3882
3883 case MsgMediaReady:
3884 if (media_info) {
3885 ImageMedia *im = static_cast <ImageMedia *> (media_info->media);
3886 if (im && !im->isEmpty ())
3887 im->sizes (size);
3888 }
3889 break;
3890
3891 default:
3892 break;
3893 }
3894 }
3895 MediaType::message (msg, content);
3896 }
3897
role(RoleType msg,void * content)3898 void *SMIL::RefMediaType::role (RoleType msg, void *content)
3899 {
3900 if (RolePlaylist == msg) {
3901 if (caption ().isEmpty () &&
3902 !src.isEmpty () &&
3903 !external_tree &&
3904 (m_type == "video" || m_type == "audio"))
3905 setCaption (src);
3906 return !caption ().isEmpty () ? (PlaylistRole *) this : NULL;
3907 }
3908 return MediaType::role (msg, content);
3909 }
3910
playType()3911 Node::PlayType SMIL::RefMediaType::playType ()
3912 {
3913 if (media_info && media_info->media)
3914 switch (media_info->media->type ()) {
3915 case MediaManager::AudioVideo:
3916 return play_type_video;
3917 case MediaManager::Image:
3918 return play_type_image;
3919 default:
3920 break;
3921 }
3922 return play_type_unknown;
3923 }
3924
3925 //-----------------------------------------------------------------------------
3926
TextMediaType(NodePtr & d)3927 KDE_NO_CDTOR_EXPORT SMIL::TextMediaType::TextMediaType (NodePtr & d)
3928 : SMIL::MediaType (d, "text", id_node_text) {}
3929
init()3930 KDE_NO_EXPORT void SMIL::TextMediaType::init () {
3931 if (Runtime::TimingsInitialized > runtime->timingstate) {
3932 font_size = TextMedia::defaultFontSize ();
3933 font_color = 0;
3934 font_name = "sans";
3935 halign = align_left;
3936
3937 MediaType::init ();
3938 }
3939 }
3940
prefetch()3941 KDE_NO_EXPORT void SMIL::TextMediaType::prefetch () {
3942 if (!media_info) {
3943 media_info = new MediaInfo (this, MediaManager::Text);
3944 media_info->wget (absolutePath ());
3945 }
3946 }
3947
3948 void
parseParam(const TrieString & name,const QString & val)3949 SMIL::TextMediaType::parseParam (const TrieString &name, const QString &val) {
3950 if (name == "color" || name == "fontColor") {
3951 font_color = val.isEmpty () ? 0 : rgbFromValue (val);
3952 } else if (name == "fontFace") {
3953 if (val.toLower ().indexOf ("sans" ) < 0)
3954 font_name = "serif";
3955 } else if (name == "font-size" || name == "fontPtSize") {
3956 font_size = val.isEmpty() ? TextMedia::defaultFontSize() : (int)SizeType (val).size ();
3957 } else if (name == "fontSize") {
3958 font_size += val.isEmpty() ? TextMedia::defaultFontSize() : (int)SizeType (val).size ();
3959 } else if (name == "hAlign") {
3960 QByteArray ba = val.toLatin1 ();
3961 const char *cval = ba.constData ();
3962 if (!cval)
3963 halign = align_left;
3964 else if (!strcmp (cval, "center"))
3965 halign = align_center;
3966 else if (!strcmp (cval, "right"))
3967 halign = align_right;
3968 else
3969 halign = align_left;
3970 // TODO: expandTabs fontBackgroundColor fontSize fontStyle fontWeight hAlig vAlign wordWrap
3971 } else {
3972 MediaType::parseParam (name, val);
3973 return;
3974 }
3975 if (sub_surface) {
3976 size = SSize ();
3977 sub_surface->resize (calculateBounds (), true);
3978 }
3979 }
3980
accept(Visitor * v)3981 KDE_NO_EXPORT void SMIL::TextMediaType::accept (Visitor * v) {
3982 v->visit (this);
3983 }
3984
3985 //-----------------------------------------------------------------------------
3986
Brush(NodePtr & d)3987 KDE_NO_CDTOR_EXPORT SMIL::Brush::Brush (NodePtr & d)
3988 : SMIL::MediaType (d, "brush", id_node_brush) {}
3989
init()3990 KDE_NO_EXPORT void SMIL::Brush::init () {
3991 if (Runtime::TimingsInitialized > runtime->timingstate)
3992 color.init ();
3993 MediaType::init ();
3994 }
3995
accept(Visitor * v)3996 KDE_NO_EXPORT void SMIL::Brush::accept (Visitor * v) {
3997 v->visit (this);
3998 }
3999
parseParam(const TrieString & param,const QString & val)4000 KDE_NO_EXPORT void SMIL::Brush::parseParam (const TrieString ¶m, const QString &val) {
4001 if (param == "color") {
4002 color.setColor (val);
4003 Surface *s = surface ();
4004 if (s)
4005 s->repaint ();
4006 } else {
4007 MediaType::parseParam (param, val);
4008 }
4009 }
4010
4011 //-----------------------------------------------------------------------------
4012
SmilText(NodePtr & d)4013 KDE_NO_CDTOR_EXPORT SMIL::SmilText::SmilText (NodePtr &d)
4014 : Element (d, id_node_smil_text),
4015 runtime (new Runtime (this)) {}
4016
~SmilText()4017 KDE_NO_CDTOR_EXPORT SMIL::SmilText::~SmilText () {
4018 delete runtime;
4019 }
4020
init()4021 void SMIL::SmilText::init () {
4022 if (Runtime::TimingsInitialized > runtime->timingstate) {
4023 background_color.init ();
4024 transition.init ();
4025 props.init ();
4026 RegionBase *rb = static_cast<SMIL::RegionBase *> (region_node.ptr ());
4027 if (rb) {
4028 props.mask (rb->font_props);
4029 media_opacity = rb->media_opacity;
4030 } else {
4031 media_opacity.init ();
4032 }
4033 Element::init ();
4034 runtime->initialize ();
4035 }
4036 }
4037
activate()4038 void SMIL::SmilText::activate () {
4039 SMIL::RegionBase *r = findRegion (this, param (Ids::attr_region));
4040 if (r)
4041 region_node = r;
4042 init (); // sets all attributes
4043 setState (state_activated);
4044 runtime->start ();
4045 }
4046
begin()4047 void SMIL::SmilText::begin () {
4048 RegionBase *rb = static_cast<SMIL::RegionBase *> (region_node.ptr ());
4049 transition.cancelTimer (this); // eg transOut and we're repeating
4050 if (rb) {
4051 region_attach.connect (rb, MsgSurfaceAttach, this);
4052 rb->repaint ();
4053 transition.begin (this, runtime);
4054 }
4055 setState (state_began);
4056 for (NodePtr c = firstChild (); c; c = c->nextSibling ())
4057 c->activate ();
4058
4059 }
4060
finish()4061 void SMIL::SmilText::finish () {
4062 transition.transition_updater.disconnect ();
4063 runtime->finish ();
4064 }
4065
deactivate()4066 void SMIL::SmilText::deactivate () {
4067 transition.finish (this);
4068 region_attach.disconnect ();
4069 if (text_surface) {
4070 text_surface->repaint ();
4071 text_surface->remove ();
4072 text_surface = NULL;
4073 }
4074 sizes.resetSizes ();
4075 runtime->init ();
4076 Element::deactivate ();
4077 }
4078
reset()4079 void SMIL::SmilText::reset () {
4080 runtime->init ();
4081 Element::reset ();
4082 }
4083
childFromTag(const QString & tag)4084 Node *SMIL::SmilText::childFromTag (const QString &tag) {
4085 QByteArray ba = tag.toLatin1 ();
4086 const char *ctag = ba.constData ();
4087 if (!strcmp (ctag, "tev"))
4088 return new TemporalMoment (m_doc, id_node_tev, ba);
4089 if (!strcmp (ctag, "clear"))
4090 return new TemporalMoment (m_doc, id_node_clear, ba);
4091 return fromTextFlowGroup (m_doc, tag);
4092 }
4093
parseParam(const TrieString & name,const QString & value)4094 void SMIL::SmilText::parseParam (const TrieString &name, const QString &value) {
4095 if (props.parseParam (name, value)
4096 || sizes.setSizeParam (name, value)
4097 || parseBackgroundParam (background_color, name, value)
4098 || parseMediaOpacityParam (media_opacity, name, value)) {
4099 message (MsgMediaUpdated);
4100 } else if (!runtime->parseParam (name, value)
4101 && !parseTransitionParam (this, transition, runtime, name, value)) {
4102 Element::parseParam (name, value);
4103 }
4104 }
4105
updateBounds(bool remove)4106 void SMIL::SmilText::updateBounds (bool remove) {
4107 if (text_surface) {
4108 SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
4109 Surface *rs = (Surface *) region_node->role (RoleDisplay);
4110 if (rs) {
4111 SRect b = rs->bounds;
4112 Single x, y, w = size.width, h = size.height;
4113 sizes.calcSizes (this, &rb->sizes, b.width(), b.height(), x, y, w, h);
4114 if (!size.isEmpty () && w > 0 && h > 0) {
4115 w = size.width;
4116 h = size.height;
4117 }
4118 text_surface->resize (SRect (x, y, w, h), remove);
4119 }
4120 }
4121 }
4122
message(MessageType msg,void * content)4123 void SMIL::SmilText::message (MessageType msg, void *content) {
4124 switch (msg) {
4125
4126 case MsgSurfaceBoundsUpdate:
4127 updateBounds (!!content);
4128 return;
4129
4130 case MsgStateFreeze:
4131 if (!runtime->active () && text_surface) {
4132 text_surface->repaint ();
4133 text_surface->remove ();
4134 text_surface = NULL;
4135 }
4136 return;
4137
4138 case MsgChildFinished:
4139 if (unfinished ())
4140 runtime->tryFinish ();
4141 return;
4142
4143 case MsgMediaUpdated:
4144 if (surface ()) {
4145 text_surface->parentNode ()->repaint ();
4146 text_surface->remove ();
4147 text_surface = NULL;
4148 }
4149 return;
4150
4151 default:
4152 break;
4153 }
4154 if (!transition.handleMessage (this, runtime, surface (), msg, content)) {
4155 if ((int) msg >= (int) Runtime::DurLastDuration)
4156 Element::message (msg, content);
4157 else
4158 runtime->message (msg, content);
4159 }
4160 }
4161
role(RoleType msg,void * content)4162 void *SMIL::SmilText::role (RoleType msg, void *content) {
4163 switch (msg) {
4164
4165 case RoleTiming:
4166 return runtime;
4167
4168 case RoleDisplay:
4169 return surface ();
4170
4171 case RoleSizer:
4172 return &sizes;
4173
4174 case RoleReceivers: {
4175 MessageType msgt = (MessageType) (long) content;
4176 ConnectionList *l = mouse_listeners.receivers (msgt);
4177 if (l)
4178 return l;
4179 if (MsgSurfaceAttach == msgt)
4180 return &media_attached;
4181 if (MsgChildTransformedIn == msgt)
4182 return &transition.m_TransformedIn;
4183 } // fall through
4184
4185 default:
4186 break;
4187 }
4188 void *response = runtime->role (msg, content);
4189 if (response == MsgUnhandled)
4190 return Element::role (msg, content);
4191 return response;
4192 }
4193
surface()4194 Surface *SMIL::SmilText::surface () {
4195 if (!runtime->active ()) {
4196 if (text_surface) {
4197 text_surface->remove ();
4198 text_surface = NULL;
4199 }
4200 } else if (region_node && !text_surface) {
4201 Surface *rs = (Surface *) region_node->role (RoleDisplay);
4202 if (rs) {
4203 text_surface = rs->createSurface (this, SRect ());
4204 text_surface->setBackgroundColor (background_color.color);
4205 size = SSize ();
4206 updateBounds (false);
4207 }
4208 }
4209 return text_surface.ptr ();
4210 }
4211
4212 //-----------------------------------------------------------------------------
4213
init()4214 void SmilTextProperties::init () {
4215 font_color = -1;
4216 background_color = -1;
4217 text_direction = DirInherit;
4218 font_family = "sans";
4219 font_size = -1;
4220 font_style = StyleInherit;
4221 font_weight = WeightInherit;
4222 text_mode = ModeInherit;
4223 text_place = PlaceInherit;
4224 text_style = "";
4225 text_wrap = WrapInherit;
4226 space = SpaceDefault;
4227 text_writing = WritingLrTb;
4228 text_align = AlignInherit;
4229 }
4230
parseParam(const TrieString & name,const QString & val)4231 bool SmilTextProperties::parseParam(const TrieString &name, const QString &val) {
4232 if (name == "textWrap") {
4233 // { Wrap, NoWrap, WrapInherit } text_wrap;
4234 } else if (name == "space" /*xml:space*/) {
4235 // { SpaceDefault, SpacePreserve } space;
4236 } else if (name == "textAlign") {
4237 if (val == "left")
4238 text_align = AlignLeft;
4239 else if (val == "center")
4240 text_align = AlignCenter;
4241 else if (val == "right")
4242 text_align = AlignRight;
4243 // start, end
4244 else
4245 text_align = AlignInherit;
4246 } else if (name == "textBackgroundColor") {
4247 background_color = rgbFromValue (val);
4248 } else if (name == "textColor") {
4249 font_color = rgbFromValue (val);
4250 } else if (name == "textDirection") {
4251 if (val == "ltr")
4252 text_direction = DirLtr;
4253 else if (val == "rtl")
4254 text_direction = DirRtl;
4255 else
4256 text_direction = DirInherit;
4257 // DirLtro, DirRtlo
4258 } else if (name == "textFontFamily") {
4259 font_family = val;
4260 } else if (name == "textFontSize") {
4261 font_size = SizeType (val);
4262 } else if (name == "textFontStyle") {
4263 if (val == "normal")
4264 font_style = StyleNormal;
4265 else if (val == "italic")
4266 font_style = StyleItalic;
4267 else if (val == "oblique")
4268 font_style = StyleOblique;
4269 else if (val == "reverseOblique")
4270 font_style = StyleRevOblique;
4271 else
4272 font_style = StyleInherit;
4273 } else if (name == "textFontWeight") {
4274 if (val == "normal")
4275 font_weight = WeightNormal;
4276 else if (val == "bold")
4277 font_weight = WeightBold;
4278 else
4279 font_weight = WeightInherit;
4280 } else if (name == "textMode") {
4281 // { ModeAppend, ModeReplace, ModeInherit } text_mode;
4282 } else if (name == "textPlace") {
4283 //enum { PlaceStart, PlaceCenter, PlaceEnd, PlaceInherit } text_place;
4284 } else if (name == "textStyle") {
4285 text_style = val;
4286 } else if (name == "textWritingMode") {
4287 // { WritingLrTb, WritingRlTb, WritingTbLr, WritingTbRl } text_writing;
4288 } else {
4289 return false;
4290 }
4291 return true;
4292 }
4293
mask(const SmilTextProperties & props)4294 void SmilTextProperties::mask (const SmilTextProperties &props) {
4295 if ((float)props.font_size.size () > 0.1)
4296 font_size = props.font_size;
4297 if (props.font_color > -1)
4298 font_color = props.font_color;
4299 if (props.background_color > -1)
4300 background_color = props.background_color;
4301 if (StyleInherit != props.font_style)
4302 font_style = props.font_style;
4303 if (WeightInherit != props.font_weight)
4304 font_weight = props.font_weight;
4305 if (AlignInherit != props.text_align)
4306 text_align = props.text_align;
4307 font_family = props.font_family;
4308 }
4309
4310 KDE_NO_CDTOR_EXPORT
TextFlow(NodePtr & doc,short id,const QByteArray & t)4311 SMIL::TextFlow::TextFlow (NodePtr &doc, short id, const QByteArray &t)
4312 : Element (doc, id), tag (t) {}
4313
~TextFlow()4314 KDE_NO_CDTOR_EXPORT SMIL::TextFlow::~TextFlow () {}
4315
init()4316 void SMIL::TextFlow::init () {
4317 props.init ();
4318 Element::init ();
4319 }
4320
activate()4321 void SMIL::TextFlow::activate () {
4322 init ();
4323 Element::activate ();
4324 }
4325
childFromTag(const QString & tag)4326 Node *SMIL::TextFlow::childFromTag (const QString &tag) {
4327 return fromTextFlowGroup (m_doc, tag);
4328 }
4329
parseParam(const TrieString & name,const QString & val)4330 void SMIL::TextFlow::parseParam(const TrieString &name, const QString &val) {
4331 if (!props.parseParam (name, val))
4332 Element::parseParam (name, val);
4333 }
4334
TemporalMoment(NodePtr & doc,short id,const QByteArray & t)4335 SMIL::TemporalMoment::TemporalMoment (NodePtr &doc, short id, const QByteArray &t)
4336 : Element (doc, id),
4337 runtime (new Runtime (this)),
4338 tag (t) {}
4339
~TemporalMoment()4340 SMIL::TemporalMoment::~TemporalMoment () {
4341 delete runtime;
4342 }
4343
init()4344 void SMIL::TemporalMoment::init () {
4345 if (Runtime::TimingsInitialized > runtime->timingstate) {
4346 Element::init ();
4347 runtime->initialize ();
4348 }
4349 }
4350
activate()4351 void SMIL::TemporalMoment::activate () {
4352 init ();
4353 setState (state_activated);
4354 runtime->start ();
4355 }
4356
begin()4357 void SMIL::TemporalMoment::begin () {
4358 parentNode ()->message (MsgMediaUpdated);
4359 Element::begin ();
4360 }
4361
deactivate()4362 void SMIL::TemporalMoment::deactivate () {
4363 runtime->init ();
4364 Element::deactivate ();
4365 }
4366
childFromTag(const QString & tag)4367 Node *SMIL::TemporalMoment::childFromTag (const QString & tag) {
4368 return fromTextFlowGroup (m_doc, tag);
4369 }
4370
parseParam(const TrieString & name,const QString & value)4371 void SMIL::TemporalMoment::parseParam (const TrieString &name, const QString &value) {
4372 // TODO: next
4373 if (!runtime->parseParam (name, value))
4374 Element::parseParam (name, value);
4375 }
4376
message(MessageType msg,void * content)4377 void SMIL::TemporalMoment::message (MessageType msg, void *content) {
4378 if ((int) msg >= (int) Runtime::DurLastDuration)
4379 Element::message (msg, content);
4380 else
4381 runtime->message (msg, content);
4382 }
4383
role(RoleType msg,void * content)4384 void *SMIL::TemporalMoment::role (RoleType msg, void *content) {
4385 if (RoleTiming == msg)
4386 return runtime;
4387 void *response = runtime->role (msg, content);
4388 if (response == MsgUnhandled)
4389 return Element::role (msg, content);
4390 return response;
4391 }
4392
4393 //-----------------------------------------------------------------------------
4394
StateValue(NodePtr & d,short _id)4395 SMIL::StateValue::StateValue (NodePtr &d, short _id)
4396 : Element (d, _id), ref (NULL), runtime (new Runtime (this)) {
4397 }
4398
~StateValue()4399 SMIL::StateValue::~StateValue () {
4400 delete runtime;
4401 delete ref;
4402 }
4403
init()4404 void SMIL::StateValue::init () {
4405 if (Runtime::TimingsInitialized > runtime->timingstate) {
4406 SMIL::Smil *smil = SMIL::Smil::findSmilNode (this);
4407 if (smil)
4408 state = smil->state_node.ptr ();
4409 Element::init ();
4410 runtime->initialize ();
4411 }
4412 }
4413
activate()4414 void SMIL::StateValue::activate () {
4415 init ();
4416 setState (state_activated);
4417 for (Attribute *a = attributes ().first (); a; a = a->nextSibling ()) {
4418 QString v = a->value ();
4419 int p = v.indexOf ('{');
4420 if (p > -1) {
4421 int q = v.indexOf ('}', p + 1);
4422 if (q > -1)
4423 parseParam (a->name (), applySubstitution (this, v, p, q));
4424 }
4425 }
4426 runtime->start ();
4427 }
4428
finish()4429 void SMIL::StateValue::finish () {
4430 runtime->finish ();
4431 }
4432
deactivate()4433 void SMIL::StateValue::deactivate () {
4434 if (unfinished ())
4435 finish ();
4436 delete ref;
4437 ref = NULL;
4438 runtime->init ();
4439 Element::deactivate ();
4440 }
4441
reset()4442 void SMIL::StateValue::reset () {
4443 runtime->init ();
4444 Element::reset ();
4445 }
4446
parseParam(const TrieString & para,const QString & val)4447 void SMIL::StateValue::parseParam (const TrieString ¶, const QString &val) {
4448 if (para == Ids::attr_value) {
4449 value = val;
4450 } else if (para == "ref") {
4451 delete ref;
4452 if (state)
4453 ref = evaluateExpr(val.toUtf8(), "data");
4454 else
4455 ref = NULL;
4456 } else if (!runtime->parseParam (para, val)) {
4457 Element::parseParam (para, val);
4458 }
4459 }
4460
message(MessageType msg,void * data)4461 void SMIL::StateValue::message (MessageType msg, void *data) {
4462 if ((int) msg >= (int) Runtime::DurLastDuration)
4463 Element::message (msg, data);
4464 else
4465 runtime->message (msg, data);
4466 }
4467
role(RoleType msg,void * data)4468 void *SMIL::StateValue::role (RoleType msg, void *data) {
4469 switch (msg) {
4470
4471 case RoleTiming:
4472 return runtime;
4473
4474 default:
4475 break;
4476 }
4477 void *response = runtime->role (msg, data);
4478 if (response == MsgUnhandled)
4479 return Element::role (msg, data);
4480 return response;
4481 }
4482
4483 //-----------------------------------------------------------------------------
4484
init()4485 void SMIL::NewValue::init () {
4486 where = SMIL::State::child;
4487 StateValue::init ();
4488 }
4489
begin()4490 void SMIL::NewValue::begin () {
4491 SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4492 if (name.isEmpty () || !st) {
4493 kWarning () << "name is empty or no state";
4494 } else {
4495 if (!ref)
4496 ref = evaluateExpr ("/data");
4497 ref->setRoot (st);
4498 Expression::iterator it = ref->begin(), e = ref->end();
4499 if (it != e && it->node) {
4500 if (name.startsWith(QChar('@')) && it->node->isElementNode())
4501 static_cast<Element*>(it->node)->setAttribute(name.mid(1), value);
4502 else
4503 st->newValue(it->node, where, name, value);
4504 }
4505 }
4506 }
4507
parseParam(const TrieString & para,const QString & val)4508 void SMIL::NewValue::parseParam (const TrieString ¶, const QString &val) {
4509 if (para == Ids::attr_name)
4510 name = val;
4511 else if (para == "where") {
4512 if (val == "before")
4513 where = SMIL::State::before;
4514 else if (val == "after")
4515 where = SMIL::State::after;
4516 else
4517 where = SMIL::State::child;
4518 } else {
4519 StateValue::parseParam (para, val);
4520 }
4521 }
4522
4523 //-----------------------------------------------------------------------------
4524
begin()4525 void SMIL::SetValue::begin () {
4526 SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4527 if (!ref || !st) {
4528 kWarning () << "ref is empty or no state";
4529 } else {
4530 ref->setRoot (st);
4531 Expression::iterator it = ref->begin(), e = ref->end();
4532 if (it != e && it->node) {
4533 if (it->attr && it->node->isElementNode ())
4534 static_cast<Element*>(it->node)->setAttribute(it->attr->name(), value);
4535 else
4536 st->setValue(it->node, value);
4537 }
4538 }
4539 }
4540
4541 //-----------------------------------------------------------------------------
4542
begin()4543 void SMIL::DelValue::begin () {
4544 SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4545 if (!ref || !st) {
4546 kWarning () << "ref is empty or no state";
4547 } else {
4548 ref->setRoot (st);
4549 Expression::iterator it = ref->begin(), e = ref->end();
4550 while (it != e) {
4551 if (it->attr && it->node->isElementNode ())
4552 static_cast<Element*>(it->node)->setAttribute(it->attr->name(), QString());
4553 else
4554 it->node->parentNode()->removeChild(it->node);
4555 ref->setRoot (st);
4556 it = ref->begin();
4557 }
4558 }
4559 }
4560
4561 //-----------------------------------------------------------------------------
4562
init()4563 void SMIL::Send::init () {
4564 method = SMIL::State::get;
4565 replace = SMIL::State::instance;
4566 StateValue::init ();
4567 }
4568
begin()4569 void SMIL::Send::begin () {
4570 SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4571 if (action.isEmpty () || !st) {
4572 kWarning () << "action is empty or no state";
4573 } else {
4574 Smil *s = SMIL::Smil::findSmilNode (this);
4575 if (s) {
4576 delete media_info;
4577 media_info = new MediaInfo (this, MediaManager::Text);
4578 Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
4579 QString url = mrl ? KURL (mrl->absolutePath(), action).url() : action;
4580 if (SMIL::State::get == method && replace == SMIL::State::instance) {
4581 // TODO compose GET url
4582 media_info->wget (url, st->domain ());
4583 } else // TODO ..
4584 qDebug("unsupported method %d replace %d", method, replace);
4585 }
4586 }
4587 }
4588
deactivate()4589 void SMIL::Send::deactivate () {
4590 delete media_info;
4591 media_info = NULL;
4592 action.clear ();
4593 StateValue::deactivate ();
4594 }
4595
parseParam(const TrieString & para,const QString & val)4596 void SMIL::Send::parseParam (const TrieString ¶, const QString &val) {
4597 if (para == "action") {
4598 action = val;
4599 } else if (para == "method") {
4600 if (val == "put")
4601 method = SMIL::State::put;
4602 else
4603 method = SMIL::State::get;
4604 } else if (para == "replace") {
4605 if (val == "all")
4606 replace = SMIL::State::all;
4607 else if (val == "none")
4608 replace = SMIL::State::none;
4609 else
4610 replace = SMIL::State::instance;
4611 } else if (para == "target") {
4612 delete ref;
4613 if (state)
4614 ref = evaluateExpr(val.toUtf8(), "data");
4615 else
4616 ref = NULL;
4617 } else {
4618 StateValue::parseParam (para, val);
4619 }
4620 }
4621
message(MessageType msg,void * content)4622 void SMIL::Send::message (MessageType msg, void *content) {
4623 SMIL::State *st = static_cast <SMIL::State *> (state.ptr ());
4624 switch (msg) {
4625
4626 case MsgMediaReady: {
4627 Node *target = NULL;
4628 if (!ref && SMIL::State::instance == replace)
4629 ref = evaluateExpr ("/data");
4630 if (ref) {
4631 ref->setRoot (st);
4632 Expression::iterator it = ref->begin(), e = ref->end();
4633 if (it != e)
4634 target = it->node;
4635 }
4636 if (target) {
4637 Node *parent = target->parentNode ();
4638 Node *next = target->nextSibling ();
4639 bool changed = target->firstChild ();
4640 target->clearChildren ();
4641 if (media_info && media_info->media) {
4642 QTextStream in (&((TextMedia *)media_info->media)->text);
4643 readXML (target, in, QString ());
4644 if (target->firstChild ()) {
4645 NodePtr store = target->firstChild ();
4646 parent->removeChild (target);
4647 parent->insertBefore (store, next);
4648 target = store;
4649 changed = true;
4650 }
4651 }
4652 if (changed)
4653 st->stateChanged (target);
4654 }
4655 delete media_info;
4656 media_info = NULL;
4657 return;
4658 }
4659 default:
4660 break;
4661 }
4662 StateValue::message (msg, content);
4663 }
4664
4665 //-----------------------------------------------------------------------------
4666
AnimateGroup(NodePtr & d,short _id)4667 KDE_NO_CDTOR_EXPORT SMIL::AnimateGroup::AnimateGroup (NodePtr &d, short _id)
4668 : Element (d, _id),
4669 runtime (new Runtime (this)),
4670 modification_id (-1) {}
4671
~AnimateGroup()4672 KDE_NO_CDTOR_EXPORT SMIL::AnimateGroup::~AnimateGroup () {
4673 delete runtime;
4674 }
4675
parseParam(const TrieString & name,const QString & val)4676 void SMIL::AnimateGroup::parseParam (const TrieString &name, const QString &val) {
4677 if (name == Ids::attr_target || name == "targetElement") {
4678 target_id = val;
4679 } else if (name == "attribute" || name == "attributeName") {
4680 changed_attribute = TrieString (val);
4681 } else if (name == "to") {
4682 change_to = val;
4683 } else if (!runtime->parseParam (name, val)) {
4684 Element::parseParam (name, val);
4685 }
4686 }
4687
init()4688 KDE_NO_EXPORT void SMIL::AnimateGroup::init () {
4689 if (Runtime::TimingsInitialized > runtime->timingstate) {
4690 Element::init ();
4691 runtime->initialize ();
4692 }
4693 }
4694
activate()4695 KDE_NO_EXPORT void SMIL::AnimateGroup::activate () {
4696 init ();
4697 setState (state_activated);
4698 runtime->start ();
4699 }
4700
4701 /**
4702 * animation finished
4703 */
finish()4704 KDE_NO_EXPORT void SMIL::AnimateGroup::finish () {
4705 runtime->finish ();
4706 }
4707
reset()4708 KDE_NO_EXPORT void SMIL::AnimateGroup::reset () {
4709 Element::reset ();
4710 target_id.truncate (0);
4711 runtime->init ();
4712 }
4713
deactivate()4714 KDE_NO_EXPORT void SMIL::AnimateGroup::deactivate () {
4715 restoreModification ();
4716 if (unfinished ())
4717 finish ();
4718 runtime->init ();
4719 Element::deactivate ();
4720 }
4721
message(MessageType msg,void * data)4722 KDE_NO_EXPORT void SMIL::AnimateGroup::message (MessageType msg, void *data) {
4723 switch (msg) {
4724
4725 case MsgStateFreeze:
4726 if (!runtime->active ())
4727 restoreModification ();
4728 return;
4729
4730 case MsgStateRewind:
4731 restoreModification ();
4732 return;
4733
4734 default:
4735 break;
4736 }
4737 if ((int) msg >= (int) Runtime::DurLastDuration)
4738 Element::message (msg, data);
4739 else
4740 runtime->message (msg, data);
4741 }
4742
role(RoleType msg,void * data)4743 KDE_NO_EXPORT void *SMIL::AnimateGroup::role (RoleType msg, void *data) {
4744 switch (msg) {
4745
4746 case RoleTiming:
4747 return runtime;
4748
4749 default:
4750 break;
4751 }
4752 void *response = runtime->role (msg, data);
4753 if (response == MsgUnhandled)
4754 return Element::role (msg, data);
4755 return response;
4756 }
4757
4758
restoreModification()4759 KDE_NO_EXPORT void SMIL::AnimateGroup::restoreModification () {
4760 if (modification_id > -1 && target_element &&
4761 target_element->state > Node::state_init) {
4762 convertNode <Element> (target_element)->resetParam (
4763 changed_attribute, modification_id);
4764 }
4765 modification_id = -1;
4766 }
4767
targetElement()4768 KDE_NO_EXPORT Node *SMIL::AnimateGroup::targetElement () {
4769 if (target_id.isEmpty ()) {
4770 for (Node *p = parentNode(); p; p =p->parentNode())
4771 if (SMIL::id_node_first_mediatype <= p->id &&
4772 SMIL::id_node_last_mediatype >= p->id) {
4773 target_element = p;
4774 break;
4775 }
4776 } else {
4777 target_element = findLocalNodeById (this, target_id);
4778 }
4779 return target_element.ptr ();
4780 }
4781
4782 //-----------------------------------------------------------------------------
4783
begin()4784 KDE_NO_EXPORT void SMIL::Set::begin () {
4785 restoreModification ();
4786 Element *target = static_cast <Element *> (targetElement ());
4787 if (target)
4788 target->setParam (changed_attribute, change_to, &modification_id);
4789 else
4790 kWarning () << "target element not found" << endl;
4791 AnimateGroup::begin ();
4792 }
4793
4794 //-----------------------------------------------------------------------------
4795 /*
4796 //http://en.wikipedia.org/wiki/B%C3%A9zier_curve
4797 typedef struct {
4798 float x;
4799 float y;
4800 } Point2D;
4801
4802 static Point2D PointOnCubicBezier (Point2D *cp, float t) {
4803 float ax, bx, cx;
4804 float ay, by, cy;
4805 float tSquared, tCubed;
4806 Point2D result;
4807
4808 // calculate the polynomial coefficients
4809
4810 cx = 3.0 * (cp[1].x - cp[0].x);
4811 bx = 3.0 * (cp[2].x - cp[1].x) - cx;
4812 ax = cp[3].x - cp[0].x - cx - bx;
4813
4814 cy = 3.0 * (cp[1].y - cp[0].y);
4815 by = 3.0 * (cp[2].y - cp[1].y) - cy;
4816 ay = cp[3].y - cp[0].y - cy - by;
4817
4818 // calculate the curve point at parameter value t
4819
4820 tSquared = t * t;
4821 tCubed = tSquared * t;
4822
4823 result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
4824 result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
4825
4826 return result;
4827 }
4828 */
4829
AnimateBase(NodePtr & d,short id)4830 KDE_NO_CDTOR_EXPORT SMIL::AnimateBase::AnimateBase (NodePtr &d, short id)
4831 : AnimateGroup (d, id),
4832 anim_timer (NULL),
4833 keytimes (NULL),
4834 spline_table (NULL),
4835 keytime_count (0) {}
4836
~AnimateBase()4837 KDE_NO_CDTOR_EXPORT SMIL::AnimateBase::~AnimateBase () {
4838 if (keytimes)
4839 free (keytimes);
4840 if (spline_table)
4841 free (spline_table);
4842 }
4843
init()4844 KDE_NO_EXPORT void SMIL::AnimateBase::init () {
4845 if (Runtime::TimingsInitialized > runtime->timingstate) {
4846 if (anim_timer) {
4847 document ()->cancelPosting (anim_timer);
4848 anim_timer = NULL;
4849 }
4850 accumulate = acc_none;
4851 additive = add_replace;
4852 calcMode = calc_linear;
4853 change_from.truncate (0);
4854 change_by.truncate (0);
4855 values.clear ();
4856 if (keytimes)
4857 free (keytimes);
4858 keytimes = NULL;
4859 keytime_count = 0;
4860 if (spline_table)
4861 free (spline_table);
4862 spline_table = NULL;
4863 splines.clear ();
4864 AnimateGroup::init ();
4865 }
4866 }
4867
begin()4868 KDE_NO_EXPORT void SMIL::AnimateBase::begin () {
4869 interval = 0;
4870 if (!setInterval ())
4871 return;
4872 applyStep ();
4873 if (calc_discrete != calcMode)
4874 change_updater.connect (m_doc, MsgSurfaceUpdate, this);
4875 AnimateGroup::begin ();
4876 }
4877
finish()4878 KDE_NO_EXPORT void SMIL::AnimateBase::finish () {
4879 if (anim_timer) { // make sure timers are stopped
4880 document ()->cancelPosting (anim_timer);
4881 anim_timer = NULL;
4882 }
4883 change_updater.disconnect ();
4884 AnimateGroup::finish ();
4885 }
4886
deactivate()4887 KDE_NO_EXPORT void SMIL::AnimateBase::deactivate () {
4888 if (anim_timer) {
4889 document ()->cancelPosting (anim_timer);
4890 anim_timer = NULL;
4891 } else {
4892 change_updater.disconnect ();
4893 }
4894 if (spline_table)
4895 free (spline_table);
4896 spline_table = NULL;
4897 AnimateGroup::deactivate ();
4898 }
4899
message(MessageType msg,void * data)4900 KDE_NO_EXPORT void SMIL::AnimateBase::message (MessageType msg, void *data) {
4901 switch (msg) {
4902 case MsgEventTimer: {
4903 TimerPosting *te = static_cast <TimerPosting *> (data);
4904 if (te->event_id == anim_timer_id) {
4905 anim_timer = NULL;
4906 timerTick (0);
4907 return;
4908 }
4909 break;
4910 }
4911 case MsgSurfaceUpdate: {
4912 UpdateEvent *ue = static_cast <UpdateEvent *> (data);
4913 interval_start_time += ue->skipped_time;
4914 interval_end_time += ue->skipped_time;
4915 timerTick (ue->cur_event_time);
4916 return;
4917 }
4918 case MsgStateRewind:
4919 restoreModification ();
4920 if (anim_timer) {
4921 document ()->cancelPosting (anim_timer);
4922 anim_timer = NULL;
4923 } else {
4924 change_updater.disconnect ();
4925 }
4926 break;
4927 default:
4928 break;
4929 }
4930 AnimateGroup::message (msg, data);
4931 }
4932
parseParam(const TrieString & name,const QString & val)4933 void SMIL::AnimateBase::parseParam (const TrieString &name, const QString &val) {
4934 if (name == "from") {
4935 change_from = val;
4936 } else if (name == "by" || name == "change_by") {
4937 change_by = val;
4938 } else if (name == "values") {
4939 values = val.split (QChar (';'));
4940 } else if (name == "keyTimes") {
4941 QStringList kts = val.split (QChar (';'));
4942 if (keytimes)
4943 free (keytimes);
4944 keytime_count = kts.size ();
4945 if (0 == keytime_count) {
4946 keytimes = NULL;
4947 return;
4948 }
4949 keytimes = (float *) malloc (sizeof (float) * keytime_count);
4950 for (unsigned int i = 0; i < keytime_count; i++) {
4951 keytimes[i] = kts[i].trimmed().toDouble();
4952 if (keytimes[i] < 0.0 || keytimes[i] > 1.0)
4953 kWarning() << "animateMotion wrong keyTimes values";
4954 else if (i == 0 && keytimes[i] > 0.01)
4955 kWarning() << "animateMotion first keyTimes value not 0";
4956 else
4957 continue;
4958 free (keytimes);
4959 keytimes = NULL;
4960 keytime_count = 0;
4961 return;
4962 }
4963 } else if (name == "keySplines") {
4964 splines = val.split (QChar (';'));
4965 } else if (name == "calcMode") {
4966 if (val == QString::fromLatin1 ("discrete"))
4967 calcMode = calc_discrete;
4968 else if (val == QString::fromLatin1 ("linear"))
4969 calcMode = calc_linear;
4970 else if (val == QString::fromLatin1 ("paced"))
4971 calcMode = calc_paced;
4972 else if (val == QString::fromLatin1 ("spline"))
4973 calcMode = calc_spline;
4974 } else
4975 AnimateGroup::parseParam (name, val);
4976 }
4977
cubicBezier(float ax,float bx,float cx,float ay,float by,float cy,float t)4978 static SMIL::AnimateBase::Point2D cubicBezier (float ax, float bx, float cx,
4979 float ay, float by, float cy, float t) {
4980 float tSquared, tCubed;
4981 SMIL::AnimateBase::Point2D result;
4982
4983 /* calculate the curve point at parameter value t */
4984
4985 tSquared = t * t;
4986 tCubed = tSquared * t;
4987
4988 result.x = (ax * tCubed) + (bx * tSquared) + (cx * t);
4989 result.y = (ay * tCubed) + (by * tSquared) + (cy * t);
4990
4991 return result;
4992 }
4993
4994 static
cubicBezier(SMIL::AnimateBase::Point2D * table,int a,int b,float x)4995 float cubicBezier (SMIL::AnimateBase::Point2D *table, int a, int b, float x) {
4996 if (b > a + 1) {
4997 int mid = (a + b) / 2;
4998 if (table[mid].x > x)
4999 return cubicBezier (table, a, mid, x);
5000 else
5001 return cubicBezier (table, mid, b, x);
5002 }
5003 return table[a].y + (x - table[a].x) / (table[b].x - table[a].x) * (table[b].y - table[a].y);
5004 }
5005
5006
setInterval()5007 bool SMIL::AnimateBase::setInterval () {
5008 int cs = runtime->durTime ().offset;
5009 if (keytime_count > interval + 1)
5010 cs = (int) (cs * (keytimes[interval+1] - keytimes[interval]));
5011 else if (keytime_count > interval && calc_discrete == calcMode)
5012 cs = (int) (cs * (1.0 - keytimes[interval]));
5013 else if (values.size () > 0 && calc_discrete == calcMode)
5014 cs /= values.size ();
5015 else if (values.size () > 1)
5016 cs /= values.size () - 1;
5017 if (cs < 0) {
5018 kWarning () << "animateMotion has no valid duration interval " <<
5019 interval << endl;
5020 runtime->doFinish ();
5021 return false;
5022 }
5023 interval_start_time = document ()->last_event_time;
5024 interval_end_time = interval_start_time + 10 * cs;
5025 switch (calcMode) {
5026 case calc_paced: // FIXME
5027 case calc_linear:
5028 break;
5029 case calc_spline:
5030 if (splines.size () > (int)interval) {
5031 QStringList kss = splines[interval].split (QChar (' '));
5032 control_point[0] = control_point[1] = 0;
5033 control_point[2] = control_point[3] = 1;
5034 if (kss.size () == 4) {
5035 for (int i = 0; i < 4; ++i) {
5036 control_point[i] = kss[i].toDouble();
5037 if (control_point[i] < 0 || control_point[i] > 1) {
5038 kWarning () << "keySplines values not between 0-1"
5039 << endl;
5040 control_point[i] = i > 1 ? 1 : 0;
5041 break;
5042 }
5043 }
5044 if (spline_table)
5045 free (spline_table);
5046 spline_table = (Point2D *) malloc (100 * sizeof (Point2D));
5047
5048 /* calculate the polynomial coefficients */
5049 float ax, bx, cx;
5050 float ay, by, cy;
5051 cx = 3.0 * control_point[0];
5052 bx = 3.0 * (control_point[2] - control_point[0]) - cx;
5053 ax = 1.0 - cx - bx;
5054
5055 cy = 3.0 * control_point[1];
5056 by = 3.0 * (control_point[3] - control_point[1]) - cy;
5057 ay = 1.0 - cy - by;
5058
5059 for (int i = 0; i < 100; ++i)
5060 spline_table[i] = cubicBezier (ax, bx, cx, ay, by, cy, 1.0*i/100);
5061 } else {
5062 kWarning () << "keySplines " << interval <<
5063 " has not 4 values" << endl;
5064 }
5065 }
5066 break;
5067 case calc_discrete:
5068 anim_timer = document ()->post (this,
5069 new TimerPosting (10 * cs, anim_timer_id));
5070 break;
5071 default:
5072 break;
5073 }
5074 //kDebug() << "setInterval " << steps << " " <<
5075 // cur_x.size () << "," << cur_y.size () << "=>"
5076 // << end_x.size () << "," << end_y.size () << " d:" <<
5077 // delta_x.size () << "," << delta_y.size () << endl;
5078 return true;
5079 }
5080
5081 //-----------------------------------------------------------------------------
5082
Animate(NodePtr & doc)5083 SMIL::Animate::Animate (NodePtr &doc)
5084 : AnimateBase (doc, id_node_animate),
5085 num_count (0), begin_(NULL), cur (NULL), delta (NULL), end (NULL) {
5086 }
5087
init()5088 KDE_NO_EXPORT void SMIL::Animate::init () {
5089 if (Runtime::TimingsInitialized > runtime->timingstate) {
5090 cleanUp ();
5091 AnimateBase::init ();
5092 }
5093 }
5094
cleanUp()5095 KDE_NO_EXPORT void SMIL::Animate::cleanUp () {
5096 if (anim_timer) {
5097 document ()->cancelPosting (anim_timer);
5098 anim_timer = NULL;
5099 }
5100 delete [] begin_;
5101 delete [] cur;
5102 delete [] delta;
5103 delete [] end;
5104 begin_ = cur = delta = end = NULL;
5105 num_count = 0;
5106 }
5107
deactivate()5108 KDE_NO_EXPORT void SMIL::Animate::deactivate () {
5109 cleanUp ();
5110 AnimateBase::deactivate ();
5111 }
5112
begin()5113 KDE_NO_EXPORT void SMIL::Animate::begin () {
5114 restoreModification ();
5115 cleanUp (); // FIXME: repeating doesn't reinit
5116
5117 NodePtr protect = target_element;
5118 Element *target = static_cast <Element *> (targetElement ());
5119 if (!target) {
5120 kWarning () << "target element not found";
5121 runtime->doFinish ();
5122 return;
5123 }
5124 if (values.size () < 2) {
5125 values.push_front (change_from.isEmpty ()
5126 ? target->param (changed_attribute)
5127 : change_from);
5128 if (!change_to.isEmpty ()) {
5129 values.push_back (change_to);
5130 } else if (!change_by.isEmpty ()) {
5131 SizeType b (values[0]);
5132 b += SizeType (change_by);
5133 values.push_back (b.toString ());
5134 }
5135 }
5136 if (values.size () < 2) {
5137 kWarning () << "could not determine change values";
5138 runtime->doFinish ();
5139 return;
5140 }
5141 if (calcMode != calc_discrete) {
5142 QStringList bnums = values[0].split (QString (","));
5143 QStringList enums = values[1].split (QString (","));
5144 num_count = bnums.size ();
5145 if (num_count) {
5146 begin_ = new SizeType [num_count];
5147 end = new SizeType [num_count];
5148 cur = new SizeType [num_count];
5149 delta = new SizeType [num_count];
5150 for (int i = 0; i < num_count; ++i) {
5151 begin_[i] = bnums[i];
5152 end[i] = i < enums.size () ? enums[i] : bnums[i];
5153 cur[i] = begin_[i];
5154 delta[i] = end[i];
5155 delta[i] -= begin_[i];
5156 }
5157 }
5158 }
5159 AnimateBase::begin ();
5160 }
5161
finish()5162 KDE_NO_EXPORT void SMIL::Animate::finish () {
5163 if (active () && calc_discrete != calcMode)
5164 for (int i = 0; i < num_count; ++i)
5165 if (cur[i].size () != end[i].size ()) {
5166 for (int j = 0; j < num_count; ++j)
5167 cur[j] = end[j];
5168 applyStep (); // we lost some steps ..
5169 break;
5170 }
5171 AnimateBase::finish ();
5172 }
5173
applyStep()5174 KDE_NO_EXPORT void SMIL::Animate::applyStep () {
5175 Element *target = convertNode <Element> (target_element);
5176 if (target) {
5177 if (calcMode != calc_discrete) {
5178 if (num_count) {
5179 QString val (cur[0].toString ());
5180 for (int i = 1; i < num_count; ++i)
5181 val += QChar (',') + cur[i].toString ();
5182 target->setParam (changed_attribute, val, &modification_id);
5183 }
5184 } else if ((int)interval < values.size ()) {
5185 target->setParam (changed_attribute,
5186 values[interval], &modification_id);
5187 }
5188 }
5189 }
5190
timerTick(unsigned int cur_time)5191 KDE_NO_EXPORT bool SMIL::Animate::timerTick (unsigned int cur_time) {
5192 if (cur_time && cur_time <= interval_end_time) {
5193 float gain = 1.0 * (cur_time - interval_start_time) /
5194 (interval_end_time - interval_start_time);
5195 if (gain > 1.0) {
5196 change_updater.disconnect ();
5197 gain = 1.0;
5198 }
5199 switch (calcMode) {
5200 case calc_paced: // FIXME
5201 case calc_linear:
5202 break;
5203 case calc_spline:
5204 if (spline_table)
5205 gain = cubicBezier (spline_table, 0, 99, gain);
5206 break;
5207 case calc_discrete:
5208 return false; // shouldn't come here
5209 }
5210 for (int i = 0; i < num_count; ++i) {
5211 cur[i] = delta[i];
5212 cur[i] *= gain;
5213 cur[i] += begin_[i];
5214 }
5215 applyStep ();
5216 return true;
5217 } else if (values.size () > (int) ++interval) {
5218 if (calc_discrete != calcMode) {
5219 if (values.size () <= (int) interval + 1)
5220 return false;
5221 QStringList enums = values[interval+1].split (QString (","));
5222 for (int i = 0; i < num_count; ++i) {
5223 begin_[i] = end[i];
5224 if (i < enums.size ())
5225 end[i] = enums[i];
5226 cur[i] = begin_[i];
5227 delta[i] = end[i];
5228 delta[i] -= begin_[i];
5229 }
5230 }
5231 if (setInterval ()) {
5232 applyStep ();
5233 return true;
5234 }
5235 }
5236 return false;
5237 }
5238
5239 //-----------------------------------------------------------------------------
5240
5241 static
getMotionCoordinates(const QString & coord,SizeType & x,SizeType & y)5242 bool getMotionCoordinates (const QString &coord, SizeType &x, SizeType &y) {
5243 int p = coord.indexOf (QChar (','));
5244 if (p < 0)
5245 p = coord.indexOf (QChar (' '));
5246 if (p > 0) {
5247 x = coord.left (p).trimmed ();
5248 y = coord.mid (p + 1).trimmed ();
5249 return true;
5250 }
5251 return false;
5252 }
5253
init()5254 KDE_NO_EXPORT void SMIL::AnimateMotion::init () {
5255 cur_x = cur_y = delta_x = delta_y = SizeType();
5256 AnimateBase::init ();
5257 }
5258
begin()5259 KDE_NO_EXPORT void SMIL::AnimateMotion::begin () {
5260 Node *t = targetElement ();
5261 CalculatedSizer *sizes = t ? (CalculatedSizer *) t->role (RoleSizer) : NULL;
5262 if (!sizes)
5263 return;
5264 old_sizes = *sizes;
5265 if (anim_timer) {
5266 document ()->cancelPosting (anim_timer);
5267 anim_timer = NULL;
5268 }
5269 if (change_from.isEmpty ()) {
5270 if (values.size () > 1) {
5271 getMotionCoordinates (values[0], begin_x, begin_y);
5272 getMotionCoordinates (values[1], end_x, end_y);
5273 } else {
5274 if (sizes->left.isSet ()) {
5275 begin_x = sizes->left;
5276 } else if (sizes->right.isSet() && sizes->width.isSet ()) {
5277 begin_x = sizes->right;
5278 begin_x -= sizes->width;
5279 } else {
5280 begin_x = "0";
5281 }
5282 if (sizes->top.isSet ()) {
5283 begin_y = sizes->top;
5284 } else if (sizes->bottom.isSet() && sizes->height.isSet ()) {
5285 begin_y = sizes->bottom;
5286 begin_y -= sizes->height;
5287 } else {
5288 begin_y = "0";
5289 }
5290 }
5291 } else {
5292 getMotionCoordinates (change_from, begin_x, begin_y);
5293 }
5294 if (!change_by.isEmpty ()) {
5295 getMotionCoordinates (change_by, delta_x, delta_y);
5296 end_x = begin_x;
5297 end_y = begin_y;
5298 end_x += delta_x;
5299 end_y += delta_y;
5300 } else if (!change_to.isEmpty ()) {
5301 getMotionCoordinates (change_to, end_x, end_y);
5302 }
5303 cur_x = begin_x;
5304 cur_y = begin_y;
5305 delta_x = end_x;
5306 delta_x -= begin_x;
5307 delta_y = end_y;
5308 delta_y -= begin_y;
5309 AnimateBase::begin ();
5310 }
5311
finish()5312 KDE_NO_EXPORT void SMIL::AnimateMotion::finish () {
5313 if (active ()) {
5314 if (calcMode != calc_discrete &&
5315 (cur_x.size () != end_x.size () ||
5316 cur_y.size () != end_y.size ())) {
5317 cur_x = end_x;
5318 cur_y = end_y;
5319 applyStep (); // we lost some steps ..
5320 }
5321 }
5322 AnimateBase::finish ();
5323 }
5324
restoreModification()5325 KDE_NO_EXPORT void SMIL::AnimateMotion::restoreModification () {
5326 Node *n = target_element.ptr ();
5327 CalculatedSizer *sizes = n ? (CalculatedSizer *) n->role (RoleSizer) : NULL;
5328 if (sizes) {
5329 *sizes = old_sizes;
5330 n->message (MsgSurfaceBoundsUpdate);
5331 }
5332 }
5333
applyStep()5334 KDE_NO_EXPORT void SMIL::AnimateMotion::applyStep () {
5335 Node *n = target_element.ptr ();
5336 CalculatedSizer *sizes = n ? (CalculatedSizer *) n->role (RoleSizer) : NULL;
5337 if (n->role (RoleDisplay)) {
5338 sizes->move (cur_x, cur_y);
5339 n->message (MsgSurfaceBoundsUpdate);
5340 }
5341 }
5342
timerTick(unsigned int cur_time)5343 KDE_NO_EXPORT bool SMIL::AnimateMotion::timerTick (unsigned int cur_time) {
5344 if (cur_time && cur_time <= interval_end_time) {
5345 float gain = 1.0 * (cur_time - interval_start_time) /
5346 (interval_end_time - interval_start_time);
5347 if (gain > 1.0) {
5348 change_updater.disconnect ();
5349 gain = 1.0;
5350 }
5351 switch (calcMode) {
5352 case calc_paced: // FIXME
5353 case calc_linear:
5354 break;
5355 case calc_spline:
5356 if (spline_table)
5357 gain = cubicBezier (spline_table, 0, 99, gain);
5358 break;
5359 case calc_discrete:
5360 return false; // shouldn't come here
5361 }
5362 cur_x = delta_x;
5363 cur_y = delta_y;
5364 cur_x *= gain;
5365 cur_y *= gain;
5366 cur_x += begin_x;
5367 cur_y += begin_y;
5368 applyStep ();
5369 return true;
5370 } else if (values.size () > (int) ++interval) {
5371 getMotionCoordinates (values[interval], begin_x, begin_y);
5372 cur_x = begin_x;
5373 cur_y = begin_y;
5374 if (calcMode != calc_discrete && values.size () > (int) interval + 1) {
5375 getMotionCoordinates (values[interval+1], end_x, end_y);
5376 delta_x = end_x;
5377 delta_x -= begin_x;
5378 delta_y = end_y;
5379 delta_y -= begin_y;
5380 }
5381 if (setInterval ()) {
5382 applyStep ();
5383 return true;
5384 }
5385 }
5386 return false;
5387 }
5388
5389 //-----------------------------------------------------------------------------
5390
getAnimateColor(unsigned int val,SMIL::AnimateColor::Channels & c)5391 static bool getAnimateColor (unsigned int val, SMIL::AnimateColor::Channels &c) {
5392 c.alpha = val >> 24;
5393 c.red = (val >> 16) & 0xff;
5394 c.green = (val >> 8) & 0xff;
5395 c.blue = val & 0xff;
5396 return true;
5397 }
5398
getAnimateColor(const QString & val,SMIL::AnimateColor::Channels & c)5399 static bool getAnimateColor (const QString &val, SMIL::AnimateColor::Channels &c) {
5400 if (val.isEmpty ())
5401 return getAnimateColor (0, c);
5402 QColor color (val);
5403 return getAnimateColor (color.rgba (), c);
5404 }
5405
colorNormalise(int c)5406 static short colorNormalise (int c) {
5407 if (c > 255)
5408 return 255;
5409 if (c < -255)
5410 return -255;
5411 return c;
5412 }
5413
operator *=(const float f)5414 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator *= (const float f) {
5415 alpha = colorNormalise ((int) (f * alpha));
5416 red = colorNormalise ((int) (f * red));
5417 green = colorNormalise ((int) (f * green));
5418 blue = colorNormalise ((int) (f * blue));
5419 return *this;
5420 }
5421
operator +=(const Channels & c)5422 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator += (const Channels &c) {
5423 alpha = colorNormalise ((int) alpha + c.alpha);
5424 red = colorNormalise ((int) red + c.red);
5425 green = colorNormalise ((int) green + c.green);
5426 blue = colorNormalise ((int) blue + c.blue);
5427 return *this;
5428 }
5429
operator -=(const Channels & c)5430 SMIL::AnimateColor::Channels &SMIL::AnimateColor::Channels::operator -= (const Channels &c) {
5431 alpha = colorNormalise ((int) alpha - c.alpha);
5432 red = colorNormalise ((int) red - c.red);
5433 green = colorNormalise ((int) green - c.green);
5434 blue = colorNormalise ((int) blue - c.blue);
5435 return *this;
5436 }
5437
argb()5438 unsigned int SMIL::AnimateColor::Channels::argb () {
5439 unsigned int v =
5440 (0xff000000 & ((unsigned)(alpha < 0 ? 0 : alpha) << 24)) |
5441 (0x00ff0000 & ((unsigned)(red < 0 ? 0 : red) << 16)) |
5442 (0x0000ff00 & ((unsigned)(green < 0 ? 0 : green) << 8)) |
5443 (0x000000ff & (blue < 0 ? 0 : blue));
5444 return v;
5445 }
5446
clear()5447 void SMIL::AnimateColor::Channels::clear () {
5448 alpha = red = blue = green = 0;
5449 }
5450
init()5451 KDE_NO_EXPORT void SMIL::AnimateColor::init () {
5452 cur_c.clear ();
5453 delta_c.clear ();
5454 changed_attribute = "background-color";
5455 AnimateBase::init ();
5456 }
5457
begin()5458 KDE_NO_EXPORT void SMIL::AnimateColor::begin () {
5459 Element *target = static_cast <Element *> (targetElement ());
5460 if (!target)
5461 return;
5462 if (anim_timer) {
5463 document ()->cancelPosting (anim_timer);
5464 anim_timer = NULL;
5465 }
5466 if (change_from.isEmpty ()) {
5467 if (values.size () > 1) {
5468 getAnimateColor (values[0], begin_c);
5469 getAnimateColor (values[1], end_c);
5470 } else {
5471 getAnimateColor (target->param (changed_attribute), begin_c);
5472 }
5473 } else {
5474 getAnimateColor (change_from, begin_c);
5475 }
5476 if (!change_by.isEmpty ()) {
5477 getAnimateColor (change_by, delta_c);
5478 end_c = begin_c;
5479 end_c += delta_c;
5480 } else if (!change_to.isEmpty ()) {
5481 getAnimateColor (change_to, end_c);
5482 }
5483 cur_c = begin_c;
5484 delta_c = end_c;
5485 delta_c -= begin_c;
5486 AnimateBase::begin ();
5487 }
5488
finish()5489 KDE_NO_EXPORT void SMIL::AnimateColor::finish () {
5490 if (active ()) {
5491 if (calcMode != calc_discrete && cur_c.argb () != end_c.argb ()) {
5492 cur_c = end_c;
5493 applyStep (); // we lost some steps ..
5494 }
5495 }
5496 AnimateBase::finish ();
5497 }
5498
applyStep()5499 KDE_NO_EXPORT void SMIL::AnimateColor::applyStep () {
5500 Node *target = target_element.ptr ();
5501 if (target) {
5502 QString val; // TODO make more efficient
5503 val.sprintf ("#%08x", cur_c.argb ());
5504 static_cast <Element *> (target)->setParam (changed_attribute, val);
5505 }
5506 }
5507
timerTick(unsigned int cur_time)5508 KDE_NO_EXPORT bool SMIL::AnimateColor::timerTick (unsigned int cur_time) {
5509 if (cur_time && cur_time <= interval_end_time) {
5510 float gain = 1.0 * (cur_time - interval_start_time) /
5511 (interval_end_time - interval_start_time);
5512 if (gain > 1.0) {
5513 change_updater.disconnect ();
5514 gain = 1.0;
5515 }
5516 switch (calcMode) {
5517 case calc_paced: // FIXME
5518 case calc_linear:
5519 break;
5520 case calc_spline:
5521 if (spline_table)
5522 gain = cubicBezier (spline_table, 0, 99, gain);
5523 break;
5524 case calc_discrete:
5525 return true; // shouldn't come here
5526 }
5527 cur_c = delta_c;
5528 cur_c *= gain;
5529 cur_c += begin_c;
5530 applyStep ();
5531 return true;
5532 } else if (values.size () > (int) ++interval) {
5533 getAnimateColor (values[interval], begin_c);
5534 cur_c = begin_c;
5535 if (calcMode != calc_discrete && values.size () > (int) interval + 1) {
5536 getAnimateColor (values[interval+1], end_c);
5537 delta_c = end_c;
5538 delta_c -= begin_c;
5539 }
5540 if (setInterval ()) {
5541 applyStep ();
5542 return true;
5543 }
5544 }
5545 return false;
5546 }
5547
5548 //-----------------------------------------------------------------------------
5549
activate()5550 KDE_NO_EXPORT void SMIL::Param::activate () {
5551 setState (state_activated);
5552 QString name = getAttribute (Ids::attr_name);
5553 Node * parent = parentNode ();
5554 if (!name.isEmpty () && parent && parent->isElementNode ())
5555 static_cast<Element*>(parent)->setParam (name,
5556 getAttribute (Ids::attr_value));
5557 Element::activate (); //finish (); // no livetime of itself, will deactivate
5558 }
5559
5560 //-----------------------------------------------------------------------------
5561
visit(SMIL::Layout * n)5562 KDE_NO_EXPORT void Visitor::visit (SMIL::Layout *n) {
5563 visit (static_cast <Element *> (n));
5564 }
5565
visit(SMIL::RegionBase * n)5566 KDE_NO_EXPORT void Visitor::visit (SMIL::RegionBase *n) {
5567 visit (static_cast <Element *> (n));
5568 }
5569
visit(SMIL::Seq * n)5570 KDE_NO_EXPORT void Visitor::visit (SMIL::Seq *n) {
5571 visit (static_cast <SMIL::GroupBase *> (n));
5572 }
5573
visit(SMIL::Switch * n)5574 KDE_NO_EXPORT void Visitor::visit (SMIL::Switch *n) {
5575 visit (static_cast <SMIL::GroupBase *> (n));
5576 }
5577
visit(SMIL::Par * n)5578 KDE_NO_EXPORT void Visitor::visit (SMIL::Par *n) {
5579 visit (static_cast <SMIL::GroupBase *> (n));
5580 }
5581
visit(SMIL::Excl * n)5582 KDE_NO_EXPORT void Visitor::visit (SMIL::Excl *n) {
5583 visit (static_cast <SMIL::GroupBase *> (n));
5584 }
5585
visit(SMIL::Transition * n)5586 KDE_NO_EXPORT void Visitor::visit (SMIL::Transition * n) {
5587 visit (static_cast <Element *> (n));
5588 }
5589
visit(SMIL::AnimateBase * n)5590 KDE_NO_EXPORT void Visitor::visit (SMIL::AnimateBase * n) {
5591 visit (static_cast <SMIL::AnimateGroup *> (n));
5592 }
5593
visit(SMIL::PriorityClass * n)5594 KDE_NO_EXPORT void Visitor::visit (SMIL::PriorityClass * n) {
5595 visit (static_cast <Element *> (n));
5596 }
5597
visit(SMIL::MediaType * n)5598 KDE_NO_EXPORT void Visitor::visit (SMIL::MediaType * n) {
5599 visit (static_cast <Mrl *> (n));
5600 }
5601
visit(SMIL::TextMediaType * n)5602 KDE_NO_EXPORT void Visitor::visit (SMIL::TextMediaType * n) {
5603 visit (static_cast <SMIL::MediaType *> (n));
5604 }
5605
visit(SMIL::RefMediaType * n)5606 KDE_NO_EXPORT void Visitor::visit (SMIL::RefMediaType * n) {
5607 visit (static_cast <SMIL::MediaType *> (n));
5608 }
5609
visit(SMIL::Brush * n)5610 KDE_NO_EXPORT void Visitor::visit (SMIL::Brush * n) {
5611 visit (static_cast <SMIL::MediaType *> (n));
5612 }
5613
visit(SMIL::SmilText * n)5614 KDE_NO_EXPORT void Visitor::visit (SMIL::SmilText *n) {
5615 visit (static_cast <Element *> (n));
5616 }
5617
visit(SMIL::TextFlow * n)5618 KDE_NO_EXPORT void Visitor::visit (SMIL::TextFlow *n) {
5619 visit (static_cast <Element *> (n));
5620 }
5621
visit(SMIL::TemporalMoment * n)5622 KDE_NO_EXPORT void Visitor::visit (SMIL::TemporalMoment *n) {
5623 visit (static_cast <Element *> (n));
5624 }
5625
visit(SMIL::Anchor * n)5626 KDE_NO_EXPORT void Visitor::visit (SMIL::Anchor * n) {
5627 visit (static_cast <SMIL::LinkingBase *> (n));
5628 }
5629
visit(SMIL::Area * n)5630 KDE_NO_EXPORT void Visitor::visit (SMIL::Area * n) {
5631 visit (static_cast <SMIL::LinkingBase *> (n));
5632 }
5633