summaryrefslogtreecommitdiffstats
path: root/src/kmplayer_smil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kmplayer_smil.cpp')
-rw-r--r--src/kmplayer_smil.cpp3604
1 files changed, 3604 insertions, 0 deletions
diff --git a/src/kmplayer_smil.cpp b/src/kmplayer_smil.cpp
new file mode 100644
index 0000000..467fbaa
--- /dev/null
+++ b/src/kmplayer_smil.cpp
@@ -0,0 +1,3604 @@
+/**
+ * Copyright (C) 2005-2007 by Koos Vriezen <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <qtextstream.h>
+#include <qcolor.h>
+#include <qpixmap.h>
+#include <qmovie.h>
+#include <qimage.h>
+#include <qtextcodec.h>
+#include <qfont.h>
+#include <qapplication.h>
+#include <qregexp.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <kurl.h>
+#include <kmimetype.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+
+#include "kmplayer_smil.h"
+#include "kmplayer_rp.h"
+
+using namespace KMPlayer;
+
+namespace KMPlayer {
+static const unsigned int event_activated = (unsigned int) Runtime::dur_activated;
+const unsigned int event_inbounds = (unsigned int) Runtime::dur_inbounds;
+const unsigned int event_outbounds = (unsigned int) Runtime::dur_outbounds;
+static const unsigned int event_stopped = (unsigned int) Runtime::dur_end;
+static const unsigned int event_started = (unsigned int)Runtime::dur_start;
+static const unsigned int event_to_be_started = 1 + (unsigned int) Runtime::dur_last_dur;
+const unsigned int event_pointer_clicked = (unsigned int) event_activated;
+const unsigned int event_pointer_moved = (unsigned int) -11;
+const unsigned int event_timer = (unsigned int) -12;
+const unsigned int event_postponed = (unsigned int) -13;
+const unsigned int mediatype_attached = (unsigned int) -14;
+
+static const unsigned int started_timer_id = (unsigned int) 1;
+static const unsigned int stopped_timer_id = (unsigned int) 2;
+static const unsigned int start_timer_id = (unsigned int) 3;
+static const unsigned int dur_timer_id = (unsigned int) 4;
+static const unsigned int anim_timer_id = (unsigned int) 5;
+static const unsigned int trans_timer_id = (unsigned int) 6;
+static const unsigned int trans_out_timer_id = (unsigned int) 7;
+}
+
+/* Intrinsic duration
+ * duration_time | end_time |
+ * =======================================================================
+ * dur_media | dur_media | wait for event
+ * 0 | dur_media | only wait for child elements
+ * dur_media | 0 | intrinsic duration finished
+ */
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT bool KMPlayer::parseTime (const QString & vl, int & dur) {
+ const char * cval = vl.ascii ();
+ if (!cval) {
+ dur = 0;
+ return false;
+ }
+ int sign = 1;
+ bool fp_seen = false;
+ QString num;
+ const char * p = cval;
+ for ( ; *p; p++ ) {
+ if (*p == '+') {
+ if (!num.isEmpty ())
+ break;
+ else
+ sign = 1;
+ } else if (*p == '-') {
+ if (!num.isEmpty ())
+ break;
+ else
+ sign = -1;
+ } else if (*p >= '0' && *p <= '9') {
+ num += QChar (*p);
+ } else if (*p == '.') {
+ if (fp_seen)
+ break;
+ else
+ num += QChar (*p);
+ fp_seen = true;
+ } else if (*p == ' ') {
+ if (!num.isEmpty ())
+ break;
+ } else
+ break;
+ }
+ bool ok = false;
+ double t;
+ if (!num.isEmpty ())
+ t = sign * num.toDouble (&ok);
+ if (ok) {
+ dur = (unsigned int) (10 * t);
+ for ( ; *p; p++ ) {
+ if (*p == 'm') {
+ dur = (unsigned int) (t * 60);
+ break;
+ } else if (*p == 'h') {
+ dur = (unsigned int) (t * 60 * 60);
+ break;
+ } else if (*p != ' ')
+ break;
+ }
+ } else {
+ dur = 0;
+ return false;
+ }
+ return true;
+}
+
+static SMIL::Region * findRegion (NodePtr p, const QString & id) {
+ TrieString regionname_attr ("regionName");
+ for (NodePtr c = p->firstChild (); c; c = c->nextSibling ()) {
+ if (c->id == SMIL::id_node_region) {
+ SMIL::Region * r = convertNode <SMIL::Region> (c);
+ QString a = r->getAttribute (regionname_attr);
+ if (a.isEmpty ())
+ a = r->getAttribute (StringPool::attr_id);
+ if ((a.isEmpty () && id.isEmpty ()) || a == id) {
+ //kdDebug () << "MediaType region found " << id << endl;
+ return r;
+ }
+ }
+ SMIL::Region * r = findRegion (c, id);
+ if (r)
+ return r;
+ }
+ return 0L;
+}
+
+static SMIL::Transition * findTransition (NodePtr n, const QString & id) {
+ SMIL::Smil * s = SMIL::Smil::findSmilNode (n);
+ if (s) {
+ Node * head = s->firstChild ().ptr ();
+ while (head && head->id != SMIL::id_node_head)
+ head = head->nextSibling ().ptr ();
+ if (head)
+ for (Node * c = head->firstChild (); c; c = c->nextSibling().ptr ())
+ if (c->id == SMIL::id_node_transition &&
+ id == static_cast <Element *> (c)->
+ getAttribute (StringPool::attr_id))
+ return static_cast <SMIL::Transition *> (c);
+ }
+ return 0L;
+}
+
+static NodePtr findLocalNodeById (NodePtr n, const QString & id) {
+ //kdDebug() << "findLocalNodeById " << id << endl;
+ SMIL::Smil * s = SMIL::Smil::findSmilNode (n);
+ if (s)
+ return s->document ()->getElementById (s, id, false);
+ return 0L;
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT ToBeStartedEvent::ToBeStartedEvent (NodePtr n)
+ : Event (event_to_be_started), node (n) {}
+
+TimerEvent::TimerEvent (TimerInfoPtr tinfo)
+ : Event (event_timer), timer_info (tinfo), interval (false) {}
+
+PostponedEvent::PostponedEvent (bool postponed)
+ : Event (event_postponed), is_postponed (postponed) {}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT Runtime::Runtime (NodePtr e)
+ : timingstate (timings_reset),
+ element (e), repeat_count (0) {}
+
+KDE_NO_CDTOR_EXPORT Runtime::~Runtime () {
+ if (start_timer || duration_timer) // ugh
+ reset ();
+}
+
+KDE_NO_EXPORT void Runtime::reset () {
+ if (element) {
+ if (start_timer) {
+ element->document ()->cancelTimer (start_timer);
+ ASSERT (!start_timer);
+ }
+ if (duration_timer) {
+ element->document ()->cancelTimer (duration_timer);
+ ASSERT (!duration_timer);
+ }
+ } else {
+ start_timer = 0L;
+ duration_timer = 0L;
+ }
+ repeat_count = 0;
+ timingstate = timings_reset;
+ for (int i = 0; i < (int) durtime_last; i++) {
+ if (durations [i].connection)
+ durations [i].connection->disconnect ();
+ durations [i].durval = dur_timer;
+ durations [i].offset = 0;
+ }
+ endTime ().durval = dur_media;
+}
+
+KDE_NO_EXPORT
+void Runtime::setDurationItem (DurationTime item, const QString & val) {
+ int dur = -2; // also 0 for 'media' duration, so it will not update then
+ QString vs = val.stripWhiteSpace ();
+ QString vl = vs.lower ();
+ const char * cval = vl.ascii ();
+ int offset = 0;
+ //kdDebug () << "setDuration1 " << vl << endl;
+ if (cval && cval[0]) {
+ QString idref;
+ const char * p = cval;
+ if (parseTime (vl, offset)) {
+ dur = dur_timer;
+ } else if (!strncmp (cval, "id(", 3)) {
+ p = strchr (cval + 3, ')');
+ if (p) {
+ idref = vs.mid (3, p - cval - 3);
+ p++;
+ }
+ if (*p) {
+ const char *q = strchr (p, '(');
+ if (q)
+ p = q;
+ }
+ } else if (!strncmp (cval, "indefinite", 10)) {
+ dur = dur_infinite;
+ } else if (!strncmp (cval, "media", 5)) {
+ dur = dur_media;
+ }
+ if (dur == -2) {
+ NodePtr target;
+ const char * q = p;
+ if (idref.isEmpty ()) {
+ bool last_esc = false;
+ for ( ; *q; q++) {
+ if (*q == '\\') {
+ if (last_esc) {
+ idref += QChar ('\\');
+ last_esc = false;
+ } else
+ last_esc = true;
+ } else if (*q == '.' && !last_esc) {
+ break;
+ } else
+ idref += QChar (*q);
+ }
+ if (!*q)
+ idref = vs.mid (p - cval);
+ else
+ idref = vs.mid (p - cval, q - p);
+ }
+ ++q;
+ if (!idref.isEmpty ()) {
+ target = findLocalNodeById (element, idref);
+ if (!target)
+ kdWarning () << "Element not found " << idref << endl;
+ }
+ //kdDebug () << "setDuration q:" << q << endl;
+ if (parseTime (vl.mid (q-cval), offset)) {
+ dur = dur_start;
+ } else if (*q && !strncmp (q, "end", 3)) {
+ dur = dur_end;
+ parseTime (vl.mid (q + 3 - cval), offset);
+ } else if (*q && !strncmp (q, "begin", 5)) {
+ dur = dur_start;
+ parseTime (vl.mid (q + 5 - cval), offset);
+ } else if (*q && !strncmp (q, "activateevent", 13)) {
+ dur = dur_activated;
+ parseTime (vl.mid (q + 13 - cval), offset);
+ } else if (*q && !strncmp (q, "inboundsevent", 13)) {
+ dur = dur_inbounds;
+ parseTime (vl.mid (q + 13 - cval), offset);
+ } else if (*q && !strncmp (q, "outofboundsevent", 16)) {
+ dur = dur_outbounds;
+ parseTime (vl.mid (q + 16 - cval), offset);
+ } else
+ kdWarning () << "setDuration no match " << cval << endl;
+ if (target && dur != dur_timer) {
+ durations [(int) item].connection =
+ target->connectTo (element, dur);
+ }
+ }
+ //kdDebug () << "setDuration " << dur << " id:'" << idref << "' off:" << offset << endl;
+ }
+ durations [(int) item].durval = (Duration) dur;
+ durations [(int) item].offset = offset;
+}
+
+/**
+ * start, or restart in case of re-use, the durations
+ */
+KDE_NO_EXPORT void Runtime::begin () {
+ if (!element) {
+ reset ();
+ return;
+ }
+ //kdDebug () << "Runtime::begin " << element->nodeName() << endl;
+ if (start_timer || duration_timer)
+ convertNode <SMIL::TimedMrl> (element)->init ();
+ timingstate = timings_began;
+
+ int offset = 0;
+ bool stop = true;
+ if (beginTime ().durval == dur_start) { // check started/finished
+ Connection * con = beginTime ().connection.ptr ();
+ if (con && con->connectee &&
+ con->connectee->state >= Node::state_began) {
+ offset = beginTime ().offset;
+ if (SMIL::TimedMrl::isTimedMrl (con->connectee))
+ offset -= element->document ()->last_event_time -
+ convertNode <SMIL::TimedMrl>(con->connectee)->begin_time;
+ stop = false;
+ kdWarning() << "start trigger on started element" << endl;
+ } // else wait for start event
+ } else if (beginTime ().durval == dur_end) { // check finished
+ Connection * con = beginTime ().connection.ptr ();
+ if (con && con->connectee &&
+ con->connectee->state >= Node::state_finished) {
+ int offset = beginTime ().offset;
+ if (SMIL::TimedMrl::isTimedMrl (con->connectee))
+ offset -= element->document ()->last_event_time -
+ convertNode<SMIL::TimedMrl>(con->connectee)->finish_time;
+ stop = false;
+ kdWarning() << "start trigger on finished element" << endl;
+ } // else wait for end event
+ } else if (beginTime ().durval == dur_timer) {
+ offset = beginTime ().offset;
+ stop = false;
+ }
+ if (stop) // wait for event
+ propagateStop (false);
+ else if (offset > 0) // start timer
+ start_timer = element->document ()->setTimeout (
+ element, 100 * offset, start_timer_id);
+ else // start now
+ propagateStart ();
+}
+
+KDE_NO_EXPORT void Runtime::beginAndStart () {
+ if (element) {
+ if (start_timer || duration_timer)
+ convertNode <SMIL::TimedMrl> (element)->init ();
+ timingstate = timings_began;
+ propagateStart ();
+ }
+}
+
+KDE_NO_EXPORT
+bool Runtime::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "Runtime::parseParam " << name << "=" << val << endl;
+ if (name == StringPool::attr_begin) {
+ setDurationItem (begin_time, val);
+ if ((timingstate == timings_began && !start_timer) ||
+ timingstate == timings_stopped) {
+ if (beginTime ().offset > 0) { // create a timer for start
+ if (start_timer)
+ element->document ()->cancelTimer (start_timer);
+ if (beginTime ().durval == dur_timer)
+ start_timer = element->document ()->setTimeout
+ (element, 100 * beginTime ().offset, start_timer_id);
+ } else // start now
+ propagateStart ();
+ }
+ } else if (name == StringPool::attr_dur) {
+ setDurationItem (duration_time, val);
+ } else if (name == StringPool::attr_end) {
+ setDurationItem (end_time, val);
+ if (endTime ().durval == dur_timer &&
+ endTime ().offset > beginTime ().offset)
+ durTime ().offset = endTime ().offset - beginTime ().offset;
+ else if (endTime ().durval != dur_timer)
+ durTime ().durval = dur_media; // event
+ } else if (name == StringPool::attr_title) {
+ Mrl * mrl = static_cast <Mrl *> (element.ptr ());
+ if (mrl)
+ mrl->pretty_name = val;
+ } else if (name == "endsync") {
+ if ((durTime ().durval == dur_media || durTime ().durval == 0) &&
+ endTime ().durval == dur_media) {
+ NodePtr e = findLocalNodeById (element, val);
+ if (SMIL::TimedMrl::isTimedMrl (e)) {
+ SMIL::TimedMrl * tm = static_cast <SMIL::TimedMrl *> (e.ptr ());
+ durations [(int) end_time].connection =
+ tm->connectTo (element, event_stopped);
+ durations [(int) end_time].durval = (Duration) event_stopped;
+ }
+ }
+ } else if (name.startsWith ("repeat")) {
+ if (val.find ("indefinite") > -1)
+ repeat_count = dur_infinite;
+ else
+ repeat_count = val.toInt ();
+ } else
+ return false;
+ return true;
+}
+
+KDE_NO_EXPORT void Runtime::processEvent (unsigned int event) {
+ SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (element);
+ if (tm) {
+ if (timingstate != timings_started && beginTime ().durval == event) {
+ if (start_timer)
+ element->document ()->cancelTimer (start_timer);
+ if (element && beginTime ().offset > 0)
+ start_timer = element->document ()->setTimeout (element,
+ 100 * beginTime ().offset, start_timer_id);
+ else //FIXME neg. offsets
+ propagateStart ();
+ if (tm->state == Node::state_finished)
+ tm->state = Node::state_activated; // rewind to activated
+ } else if (timingstate == timings_started &&
+ (unsigned int) endTime ().durval == event)
+ propagateStop (true);
+ } else
+ reset ();
+}
+
+KDE_NO_EXPORT void Runtime::propagateStop (bool forced) {
+ if (state() == timings_reset || state() == timings_stopped)
+ return; // nothing to stop
+ if (!forced && element) {
+ if (durTime ().durval == dur_media && endTime ().durval == dur_media)
+ return; // wait for external eof
+ if (endTime ().durval != dur_timer && endTime ().durval != dur_media &&
+ (state() == timings_started || beginTime().durval == dur_timer))
+ return; // wait for event
+ if (durTime ().durval == dur_infinite)
+ return; // this may take a while :-)
+ if (duration_timer)
+ return; // timerEvent will call us with forced=true
+ // bail out if a child still running
+ for (NodePtr c = element->firstChild (); c; c = c->nextSibling ())
+ if (c->unfinished ())
+ return; // a child still running
+ }
+ bool was_started (timingstate == timings_started);
+ timingstate = timings_stopped;
+ if (element) {
+ if (start_timer) {
+ element->document ()->cancelTimer (start_timer);
+ ASSERT (!start_timer);
+ }
+ if (duration_timer) {
+ element->document ()->cancelTimer (duration_timer);
+ ASSERT (!duration_timer);
+ }
+ if (was_started && element->document ()->active ())
+ element->document ()->setTimeout (element, 0, stopped_timer_id);
+ else if (element->unfinished ())
+ element->finish ();
+ } else {
+ start_timer = 0L;
+ duration_timer = 0L;
+ }
+}
+
+KDE_NO_EXPORT void Runtime::propagateStart () {
+ SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (element);
+ if (tm) {
+ tm->propagateEvent (new ToBeStartedEvent (element));
+ if (start_timer)
+ tm->document ()->cancelTimer (start_timer);
+ ASSERT (!start_timer);
+ } else
+ start_timer = 0L;
+ timingstate = timings_started;
+ element->document ()->setTimeout (element, 0, started_timer_id);
+}
+
+/**
+ * start_timer timer expired
+ */
+KDE_NO_EXPORT void Runtime::started () {
+ //kdDebug () << "Runtime::started " << (element ? element->nodeName() : "-") << endl;
+ NodePtr e = element; // element is weak
+ SMIL::TimedMrl * tm = convertNode <SMIL::TimedMrl> (e);
+ if (tm) {
+ if (start_timer)
+ tm->document ()->cancelTimer (start_timer);
+ if (durTime ().offset > 0 && durTime ().durval == dur_timer) {
+ if (duration_timer)
+ tm->document ()->cancelTimer (duration_timer);
+ duration_timer = element->document ()->setTimeout
+ (element, 100 * durTime ().offset, dur_timer_id);
+ }
+ // kdDebug () << "Runtime::started set dur timer " << durTime ().offset << endl;
+ tm->propagateEvent (new Event (event_started));
+ tm->begin ();
+ } else
+ reset ();
+}
+
+/**
+ * duration_timer timer expired or no duration set after started
+ */
+KDE_NO_EXPORT void Runtime::stopped () {
+ if (!element) {
+ reset ();
+ } else if (element->active ()) {
+ if (repeat_count == dur_infinite || 0 < repeat_count--) {
+ if (beginTime ().offset > 0 &&
+ beginTime ().durval == dur_timer) {
+ if (start_timer)
+ element->document ()->cancelTimer (start_timer);
+ start_timer = element->document ()->setTimeout
+ (element, 100 * beginTime ().offset, start_timer_id);
+ } else {
+ propagateStart ();
+ }
+ } else {
+ repeat_count = 0;
+ element->finish ();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SizeType::SizeType () {
+ reset ();
+}
+
+KDE_NO_CDTOR_EXPORT SizeType::SizeType (const QString & s) {
+ *this = s;
+}
+
+void SizeType::reset () {
+ perc_size = 0;
+ abs_size = 0;
+ isset = false;
+}
+
+SizeType & SizeType::operator = (const QString & s) {
+ QString strval (s);
+ int p = strval.find (QChar ('%'));
+ if (p > -1) {
+ strval.truncate (p);
+ perc_size = strval.toDouble (&isset);
+ } else
+ abs_size = strval.toDouble (&isset);
+ return *this;
+}
+
+SizeType & SizeType::operator += (const SizeType & s) {
+ perc_size += s.perc_size;
+ abs_size += s.abs_size;
+ return *this;
+}
+
+SizeType & SizeType::operator -= (const SizeType & s) {
+ perc_size -= s.perc_size;
+ abs_size -= s.abs_size;
+ return *this;
+}
+
+Single SizeType::size (Single relative_to) const {
+ Single s = abs_size;
+ s += perc_size * relative_to / 100;
+ return s;
+}
+
+//-----------------%<----------------------------------------------------------
+
+SRect SRect::unite (const SRect & r) const {
+ if (!(_w > 0 && _h > 0))
+ return r;
+ if (!(r._w > 0 && r._h > 0))
+ return *this;
+ Single a (_x < r._x ? _x : r._x);
+ Single b (_y < r._y ? _y : r._y);
+ return SRect (a, b,
+ ((_x + _w < r._x + r._w) ? r._x + r._w : _x + _w) - a,
+ ((_y + _h < r._y + r._h) ? r._y + r._h : _y + _h) - b);
+}
+
+SRect SRect::intersect (const SRect & r) const {
+ Single a (_x < r._x ? r._x : _x);
+ Single b (_y < r._y ? r._y : _y);
+ return SRect (a, b,
+ ((_x + _w < r._x + r._w) ? _x + _w : r._x + r._w) - a,
+ ((_y + _h < r._y + r._h) ? _y + _h : r._y + r._h) - b);
+}
+
+IRect IRect::unite (const IRect & r) const {
+ if (isEmpty ())
+ return r;
+ if (r.isEmpty ())
+ return *this;
+ int a (x < r.x ? x : r.x);
+ int b (y < r.y ? y : r.y);
+ return IRect (a, b,
+ ((x + w < r.x + r.w) ? r.x + r.w : x + w) - a,
+ ((y + h < r.y + r.h) ? r.y + r.h : y + h) - b);
+}
+
+IRect IRect::intersect (const IRect & r) const {
+ int a (x < r.x ? r.x : x);
+ int b (y < r.y ? r.y : y);
+ return IRect (a, b,
+ ((x + w < r.x + r.w) ? x + w : r.x + r.w) - a,
+ ((y + h < r.y + r.h) ? y + h : r.y + r.h) - b);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void CalculatedSizer::resetSizes () {
+ left.reset ();
+ top.reset ();
+ width.reset ();
+ height.reset ();
+ right.reset ();
+ bottom.reset ();
+ reg_point.truncate (0);
+ reg_align = QString::fromLatin1 ("topLeft");
+}
+
+static bool regPoints (const QString & str, Single & x, Single & y) {
+ QString lower = str.lower ();
+ const char * rp = lower.ascii ();
+ if (!rp)
+ return false;
+ if (!strcmp (rp, "center")) {
+ x = 50;
+ y = 50;
+ } else {
+ if (!strncmp (rp, "top", 3)) {
+ y = 0;
+ rp += 3;
+ } else if (!strncmp (rp, "mid", 3)) {
+ y = 50;
+ rp += 3;
+ } else if (!strncmp (rp, "bottom", 6)) {
+ y = 100;
+ rp += 6;
+ } else
+ return false;
+ if (!strcmp (rp, "left")) {
+ x = 0;
+ } else if (!strcmp (rp, "mid")) {
+ x = 50;
+ } else if (!strcmp (rp, "right")) {
+ x = 100;
+ } else
+ return false;
+ }
+ return true;
+}
+
+KDE_NO_EXPORT
+bool CalculatedSizer::applyRegPoints (Node * node, Single w, Single h,
+ Single & xoff, Single & yoff, Single & w1, Single & h1) {
+ if (reg_point.isEmpty ())
+ return false;
+ Single rpx, rpy, rax, ray;
+ if (!regPoints (reg_point, rpx, rpy)) {
+ node = SMIL::Smil::findSmilNode (node);
+ if (!node)
+ return false;
+ node = static_cast <SMIL::Smil *> (node)->layout_node.ptr ();
+ if (!node)
+ return false;
+ NodePtr c = node->firstChild ();
+ for (; c; c = c->nextSibling ())
+ if (c->id == SMIL::id_node_regpoint &&
+ convertNode<Element>(c)->getAttribute (StringPool::attr_id)
+ == reg_point) {
+ Single i1, i2; // dummies
+ SMIL::RegPoint *rp_elm = static_cast<SMIL::RegPoint*>(c.ptr());
+ rp_elm->sizes.calcSizes (0L, 100, 100, rpx, rpy, i1, i2);
+ QString ra = rp_elm->getAttribute ("regAlign");
+ if (!ra.isEmpty () && reg_align.isEmpty ())
+ reg_align = ra;
+ break;
+ }
+ if (!c)
+ return false; // not found
+ }
+ if (!regPoints (reg_align, rax, ray))
+ rax = ray = 0; // default back to topLeft
+ if (!(int)w1 || !(int)h1) {
+ xoff = w * (rpx - rax) / 100;
+ yoff = h * (rpy - ray) / 100;
+ w1 = w - w * (rpx > rax ? (rpx - rax) : (rax - rpx)) / 100;
+ h1 = h - h * (rpy > ray ? (rpy - ray) : (ray - rpy)) / 100;
+ } else {
+ xoff = (w * rpx - w1 * rax) / 100;
+ yoff = (h * rpy - h1 * ray) / 100;
+ }
+ // kdDebug () << "calc rp:" << reg_point << " ra:" << reg_align << " w:" << (int)w << " h:" << (int)h << " xoff:" << (int)xoff << " yoff:" << (int)yoff << " w1:" << (int)w1 << " h1:" << (int)h1 << endl;
+ return true; // success getting sizes based on regPoint
+}
+
+KDE_NO_EXPORT void CalculatedSizer::calcSizes (Node * node, Single w, Single h,
+ Single & xoff, Single & yoff, Single & w1, Single & h1) {
+ if (applyRegPoints (node, w, h, xoff, yoff, w1, h1))
+ return;
+ if (left.isSet ())
+ xoff = left.size (w);
+ else if (width.isSet ()) {
+ if (right.isSet ())
+ xoff = w - width.size (w) - right.size (w);
+ else
+ xoff = (w - width.size (w)) / 2;
+ } else
+ xoff = 0;
+ if (top.isSet ())
+ yoff = top.size (h);
+ else if (height.isSet ()) {
+ if (bottom.isSet ())
+ yoff = h - height.size (h) - bottom.size (h);
+ else
+ yoff = (h - height.size (h)) / 2;
+ } else
+ yoff = 0;
+ if (width.isSet ())
+ w1 = width.size (w);
+ else if (right.isSet ())
+ w1 = w - xoff - right.size (w);
+ else
+ w1 = w - xoff;
+ if (w1 < 0)
+ w1 = 0;
+ if (height.isSet ())
+ h1 = height.size (h);
+ else if (bottom.isSet ())
+ h1 = h - yoff - bottom.size (h);
+ else
+ h1 = h - yoff;
+ if (h1 < 0)
+ h1 = 0;
+}
+
+KDE_NO_EXPORT
+bool CalculatedSizer::setSizeParam(const TrieString &name, const QString &val, bool &dim_changed) {
+ dim_changed = true;
+ if (name == StringPool::attr_left) {
+ left = val;
+ dim_changed = right.isSet ();
+ } else if (name == StringPool::attr_top) {
+ top = val;
+ dim_changed = bottom.isSet ();
+ } else if (name == StringPool::attr_width) {
+ width = val;
+ } else if (name == StringPool::attr_height) {
+ height = val;
+ } else if (name == StringPool::attr_right) {
+ right = val;
+ dim_changed = left.isSet ();
+ } else if (name == StringPool::attr_bottom) {
+ bottom = val;
+ dim_changed = top.isSet ();
+ } else if (name == "regPoint") {
+ reg_point = val;
+ dim_changed = false;
+ } else if (name == "regAlign") {
+ reg_align = val;
+ dim_changed = false;
+ } else
+ return false;
+ return true;
+}
+
+KDE_NO_EXPORT void
+CalculatedSizer::move (const SizeType &x, const SizeType &y) {
+ if (left.isSet ()) {
+ if (right.isSet ()) {
+ right += x;
+ right -= left;
+ }
+ left = x;
+ } else if (right.isSet ()) {
+ right = x;
+ } else {
+ left = x;
+ }
+ if (top.isSet ()) {
+ if (bottom.isSet ()) {
+ bottom += y;
+ bottom -= top;
+ }
+ top = y;
+ } else if (bottom.isSet ()) {
+ bottom = y;
+ } else {
+ top = y;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT AnimateGroupData::AnimateGroupData (NodePtr e)
+ : Runtime (e), modification_id (-1) {}
+
+bool AnimateGroupData::parseParam (const TrieString &name, const QString &val) {
+ //kdDebug () << "AnimateGroupData::parseParam " << name << "=" << val << endl;
+ if (name == StringPool::attr_target || name == "targetElement") {
+ if (element)
+ target_element = findLocalNodeById (element, val);
+ } else if (name == "attribute" || name == "attributeName") {
+ changed_attribute = TrieString (val);
+ } else if (name == "to") {
+ change_to = val;
+ } else
+ return Runtime::parseParam (name, val);
+ return true;
+}
+
+/**
+ * animation finished
+ */
+KDE_NO_EXPORT void AnimateGroupData::stopped () {
+ //kdDebug () << "AnimateGroupData::stopped " << durTime ().durval << endl;
+ if (!SMIL::TimedMrl::keepContent (element))
+ restoreModification ();
+ Runtime::stopped ();
+}
+
+KDE_NO_EXPORT void AnimateGroupData::reset () {
+ restoreModification ();
+ Runtime::reset ();
+}
+
+KDE_NO_EXPORT void AnimateGroupData::restoreModification () {
+ if (modification_id > -1 && target_element &&
+ target_element->state > Node::state_init) {
+ //kdDebug () << "AnimateGroupData(" << this << ")::restoreModificatio " <<modification_id << endl;
+ convertNode <Element> (target_element)->resetParam (
+ changed_attribute, modification_id);
+ }
+ modification_id = -1;
+}
+
+//-----------------------------------------------------------------------------
+
+/**
+ * start_timer timer expired, execute it
+ */
+KDE_NO_EXPORT void SetData::started () {
+ restoreModification ();
+ if (element) {
+ if (target_element) {
+ convertNode <Element> (target_element)->setParam (
+ changed_attribute, change_to, &modification_id);
+ //kdDebug () << "SetData(" << this << ")::started " << target_element->nodeName () << "." << changed_attribute << " ->" << change_to << " modid:" << modification_id << endl;
+ } else
+ kdWarning () << "target element not found" << endl;
+ } else
+ kdWarning () << "set element disappeared" << endl;
+ AnimateGroupData::started ();
+}
+
+//-----------------------------------------------------------------------------
+
+//http://en.wikipedia.org/wiki/B%C3%A9zier_curve
+typedef struct {
+ float x;
+ float y;
+} Point2D;
+
+static Point2D PointOnCubicBezier (Point2D *cp, float t) {
+ float ax, bx, cx;
+ float ay, by, cy;
+ float tSquared, tCubed;
+ Point2D result;
+
+ /* calculate the polynomial coefficients */
+
+ cx = 3.0 * (cp[1].x - cp[0].x);
+ bx = 3.0 * (cp[2].x - cp[1].x) - cx;
+ ax = cp[3].x - cp[0].x - cx - bx;
+
+ cy = 3.0 * (cp[1].y - cp[0].y);
+ by = 3.0 * (cp[2].y - cp[1].y) - cy;
+ ay = cp[3].y - cp[0].y - cy - by;
+
+ /* calculate the curve point at parameter value t */
+
+ tSquared = t * t;
+ tCubed = tSquared * t;
+
+ result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
+ result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
+
+ return result;
+}
+
+KDE_NO_CDTOR_EXPORT AnimateData::AnimateData (NodePtr e)
+ : AnimateGroupData (e), change_by (0), steps (0) {}
+
+KDE_NO_EXPORT void AnimateData::reset () {
+ AnimateGroupData::reset ();
+ if (element) {
+ if (anim_timer)
+ element->document ()->cancelTimer (anim_timer);
+ ASSERT (!anim_timer);
+ } else
+ anim_timer = 0;
+ accumulate = acc_none;
+ additive = add_replace;
+ change_by = 0;
+ calcMode = calc_linear;
+ change_from.truncate (0);
+ change_values.clear ();
+ steps = 0;
+ change_delta = change_to_val = change_from_val = 0.0;
+ change_from_unit.truncate (0);
+}
+
+bool AnimateData::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "AnimateData::parseParam " << name << "=" << val << endl;
+ if (name == "change_by") {
+ change_by = val.toInt ();
+ } else if (name == "from") {
+ change_from = val;
+ } else if (name == "values") {
+ change_values = QStringList::split (QString (";"), val);
+ } else if (name == "calcMode") {
+ if (val == QString::fromLatin1 ("discrete"))
+ calcMode = calc_discrete;
+ else if (val == QString::fromLatin1 ("linear"))
+ calcMode = calc_linear;
+ else if (val == QString::fromLatin1 ("paced"))
+ calcMode = calc_paced;
+ } else
+ return AnimateGroupData::parseParam (name, val);
+ return true;
+}
+
+/**
+ * start_timer timer expired, execute it
+ */
+KDE_NO_EXPORT void AnimateData::started () {
+ //kdDebug () << "AnimateData::started " << durTime ().durval << endl;
+ restoreModification ();
+ if (anim_timer) {
+ kdWarning () << "AnimateData::started " << anim_timer.ptr() << endl;
+ element->document ()->cancelTimer (anim_timer);
+ }
+ bool success = false;
+ do {
+ if (!element) {
+ kdWarning () << "set element disappeared" << endl;
+ break;
+ }
+ NodePtr protect = target_element;
+ Element * target = convertNode <Element> (target_element);
+ if (!target) {
+ kdWarning () << "target element not found" << endl;
+ break;
+ }
+ if (calcMode == calc_linear) {
+ QRegExp reg ("^\\s*(-?[0-9\\.]+)(\\s*[%a-z]*)?");
+ if (change_from.isEmpty ()) {
+ if (change_values.size () > 0) // check 'values' attribute
+ change_from = change_values.first ();
+ else // take current
+ change_from = target->param (changed_attribute);
+ }
+ if (!change_from.isEmpty ()) {
+ target->setParam (changed_attribute, change_from,
+ &modification_id);
+ if (reg.search (change_from) > -1) {
+ change_from_val = reg.cap (1).toDouble ();
+ change_from_unit = reg.cap (2);
+ }
+ } else {
+ kdWarning() << "animate couldn't determine start value" << endl;
+ break;
+ }
+ if (change_to.isEmpty () && change_values.size () > 1)
+ change_to = change_values.last (); // check 'values' attribute
+ if (!change_to.isEmpty () && reg.search (change_to) > -1) {
+ change_to_val = reg.cap (1).toDouble ();
+ } else {
+ kdWarning () << "animate couldn't determine end value" << endl;
+ break;
+ }
+ steps = 20 * durTime ().offset / 5; // 40 per sec
+ if (steps > 0) {
+ anim_timer = element->document ()->setTimeout (element, 25, anim_timer_id); // 25 ms for now FIXME
+ change_delta = (change_to_val - change_from_val) / steps;
+ //kdDebug () << "AnimateData::started " << target_element->nodeName () << "." << changed_attribute << " " << change_from_val << "->" << change_to_val << " in " << steps << " using:" << change_delta << " inc" << endl;
+ success = true;
+ }
+ } else if (calcMode == calc_discrete) {
+ steps = change_values.size () - 1; // we do already the first step
+ if (steps < 1) {
+ kdWarning () << "animate needs at least two values" << endl;
+ break;
+ }
+ int interval = 100 * durTime ().offset / (1 + steps);
+ if (interval <= 0 || durTime ().durval != dur_timer) {
+ kdWarning () << "animate needs a duration time" << endl;
+ break;
+ }
+ //kdDebug () << "AnimateData::started " << target_element->nodeName () << "." << changed_attribute << " " << change_values.first () << "->" << change_values.last () << " in " << steps << " interval:" << interval << endl;
+ anim_timer = element->document ()->setTimeout (element, interval, anim_timer_id); // 50 /s for now FIXME
+ target->setParam (changed_attribute, change_values.first (),
+ &modification_id);
+ success = true;
+ }
+ } while (false);
+ if (success)
+ AnimateGroupData::started ();
+ else
+ propagateStop (true);
+}
+
+/**
+ * undo if necessary
+ */
+KDE_NO_EXPORT void AnimateData::stopped () {
+ if (element) {
+ if (anim_timer) // make sure timers are stopped
+ element->document ()->cancelTimer (anim_timer);
+ ASSERT (!anim_timer);
+ if (steps > 0 && element->active ()) {
+ steps = 0;
+ if (calcMode == calc_linear)
+ change_from_val = change_to_val;
+ applyStep (); // we lost some steps ..
+ }
+ } else
+ anim_timer = 0;
+ AnimateGroupData::stopped ();
+}
+
+KDE_NO_EXPORT void AnimateData::applyStep () {
+ Element * target = convertNode <Element> (target_element);
+ if (target && calcMode == calc_linear)
+ target->setParam (changed_attribute, QString ("%1%2").arg (
+ change_from_val).arg(change_from_unit),
+ &modification_id);
+ else if (target && calcMode == calc_discrete)
+ target->setParam (changed_attribute,
+ change_values[change_values.size () - steps -1],
+ &modification_id);
+}
+
+/**
+ * for animations
+ */
+KDE_NO_EXPORT bool AnimateData::timerTick () {
+ if (!anim_timer) {
+ kdError () << "spurious anim timer tick" << endl;
+ } else if (steps-- > 0) {
+ if (calcMode == calc_linear)
+ change_from_val += change_delta;
+ applyStep ();
+ return true;
+ } else {
+ if (element)
+ element->document ()->cancelTimer (anim_timer);
+ ASSERT (!anim_timer);
+ propagateStop (true); // not sure, actually
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT AnimateMotionData::AnimateMotionData (NodePtr e)
+ : AnimateGroupData (e), keytimes (NULL), steps (0) {}
+
+KDE_NO_CDTOR_EXPORT AnimateMotionData::~AnimateMotionData () {
+ reset ();
+}
+
+bool AnimateMotionData::checkTarget (Node *n) {
+ if (!n ||
+ (SMIL::id_node_region != n->id &&
+ !(SMIL::id_node_first_mediatype <= n->id &&
+ SMIL::id_node_last_mediatype >= n->id))) {
+ kdWarning () << "animateMotion target element not " <<
+ (n ? "supported" : "found") << endl;
+ if (element && anim_timer)
+ element->document ()->cancelTimer (anim_timer);
+ propagateStop (true);
+ return false;
+ }
+ return true;
+}
+
+KDE_NO_EXPORT void AnimateMotionData::reset () {
+ AnimateGroupData::reset ();
+ if (element) {
+ if (anim_timer)
+ element->document ()->cancelTimer (anim_timer);
+ ASSERT (!anim_timer);
+ } else
+ anim_timer = 0;
+ accumulate = acc_none;
+ additive = add_replace;
+ calcMode = calc_linear;
+ change_from.truncate (0);
+ change_by.truncate (0);
+ values.clear ();
+ delete keytimes;
+ keytimes = NULL;
+ keytime_count = 0;
+ splines.clear ();
+ steps = 0;
+ cur_x = cur_y = delta_x = delta_y = SizeType();
+}
+
+bool AnimateMotionData::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "AnimateMotionData::parseParam " << name << "=" << val << endl;
+ if (name == "from") {
+ change_from = val;
+ } else if (name == "by") {
+ change_by = val;
+ } else if (name == "values") {
+ values = QStringList::split (QString (";"), val);
+ } else if (name == "keyTimes") {
+ QStringList kts = QStringList::split (QString (";"), val);
+ delete keytimes;
+ keytime_count = kts.size ();
+ keytimes = new float [keytime_count];
+ for (int i = 0; i < keytime_count; i++) {
+ keytimes[i] = kts[i].stripWhiteSpace().toDouble();
+ if (keytimes[i] < 0.0 || keytimes[i] > 1.0)
+ kdWarning() << "animateMotion wrong keyTimes values" << endl;
+ else if (i == 0 && keytimes[i] > 0.01)
+ kdWarning() << "animateMotion first keyTimes value not 0" << endl;
+ else
+ continue;
+ delete keytimes;
+ keytimes = NULL;
+ keytime_count = 0;
+ return true;
+ }
+ } else if (name == "keySplines") {
+ splines = QStringList::split (QString (";"), val);
+ } else if (name == "calcMode") {
+ if (val == QString::fromLatin1 ("discrete"))
+ calcMode = calc_discrete;
+ else if (val == QString::fromLatin1 ("linear"))
+ calcMode = calc_linear;
+ else if (val == QString::fromLatin1 ("paced"))
+ calcMode = calc_paced;
+ else if (val == QString::fromLatin1 ("spline"))
+ calcMode = calc_spline;
+ } else
+ return AnimateGroupData::parseParam (name, val);
+ return true;
+}
+
+bool AnimateMotionData::getCoordinates (const QString &coord, SizeType &x, SizeType &y) {
+ int p = coord.find (QChar (','));
+ if (p > 0) {
+ x = coord.left (p).stripWhiteSpace ();
+ y = coord.mid (p + 1).stripWhiteSpace ();
+ return true;
+ }
+ return false;
+}
+
+bool AnimateMotionData::setInterval () {
+ int cs = 10 * durTime ().offset;
+ if (keytime_count > interval + 1)
+ cs = (int) (cs * (keytimes[interval+1] - keytimes[interval]));
+ else if (values.size () > 1)
+ cs /= values.size () - 1;
+ if (cs < 0) {
+ kdWarning () << "animateMotion has no valid duration interval " <<
+ interval << endl;
+ propagateStop (true);
+ return false;
+ }
+ steps = cs * 4 / 10; // 40 per sec
+ cur_step = 0;
+ cur_x = begin_x;
+ cur_y = begin_y;
+ delta_x = end_x;
+ delta_x -= begin_x;
+ delta_y = end_y;
+ delta_y -= begin_y;
+ switch (calcMode) {
+ case calc_paced: // FIXME
+ case calc_linear:
+ delta_x /= steps;
+ delta_y /= steps;
+ break;
+ case calc_spline:
+ if (splines.size () > interval) {
+ QStringList kss = QStringList::split (
+ QString (" "), splines[interval]);
+ control_point[0] = control_point[1] = 0;
+ control_point[2] = control_point[3] = 1;
+ if (kss.size () == 4) {
+ for (int i = 0; i < 4; ++i) {
+ control_point[i] = kss[i].toDouble();
+ if (control_point[i] < 0 || control_point[i] > 1) {
+ kdWarning () << "keySplines values not between 0-1"
+ << endl;
+ control_point[i] = i > 1 ? 1 : 0;
+ break;
+ }
+ }
+ } else {
+ kdWarning () << "keySplines " << interval <<
+ " has not 4 values" << endl;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ //kdDebug() << "setInterval " << steps << " " <<
+ // cur_x.size() << "," << cur_y.size() << "=>"
+ // << end_x.size() << "," << end_y.size() << " d:" <<
+ // delta_x.size() << "," << delta_y.size() << endl;
+ return true;
+}
+
+KDE_NO_EXPORT void AnimateMotionData::started () {
+ //kdDebug () << "AnimateMotionData::started " << durTime ().durval << endl;
+ Element *target = convertNode <Element> (target_element);
+ if (!element || !checkTarget (target))
+ return;
+ if (anim_timer)
+ element->document ()->cancelTimer (anim_timer);
+ interval = 0;
+ if (change_from.isEmpty ()) {
+ if (values.size () > 1) {
+ getCoordinates (values[0], begin_x, begin_y);
+ getCoordinates (values[1], end_x, end_y);
+ } else {
+ CalculatedSizer sizes;
+ if (SMIL::id_node_region == target->id)
+ sizes = static_cast<SMIL::Region*>(target)->sizes;
+ else if (SMIL::id_node_first_mediatype <= target->id &&
+ SMIL::id_node_last_mediatype >= target->id)
+ sizes = static_cast<SMIL::MediaType*>(target)->sizes;
+ if (sizes.left.isSet ()) {
+ begin_x = sizes.left;
+ } else if (sizes.right.isSet() && sizes.width.isSet ()) {
+ begin_x = sizes.right;
+ begin_x -= sizes.width;
+ } else {
+ begin_x = "0";
+ }
+ if (sizes.top.isSet ()) {
+ begin_y = sizes.top;
+ } else if (sizes.bottom.isSet() && sizes.height.isSet ()) {
+ begin_y = sizes.bottom;
+ begin_y -= sizes.height;
+ } else {
+ begin_y = "0";
+ }
+ }
+ } else {
+ getCoordinates (change_from, begin_x, begin_y);
+ }
+ if (!change_by.isEmpty ()) {
+ getCoordinates (change_by, delta_x, delta_y);
+ end_x = begin_x;
+ end_y = begin_y;
+ end_x += delta_x;
+ end_y += delta_y;
+ } else if (!change_to.isEmpty ()) {
+ getCoordinates (change_to, end_x, end_y);
+ }
+ if (!setInterval ())
+ return;
+ applyStep ();
+ anim_timer = element->document ()->setTimeout (element, 25, anim_timer_id);
+ AnimateGroupData::started ();
+}
+
+
+KDE_NO_EXPORT void AnimateMotionData::stopped () {
+ if (element) {
+ if (anim_timer) // make sure timers are stopped
+ element->document ()->cancelTimer (anim_timer);
+ ASSERT (!anim_timer);
+ if (cur_step < steps && element->active () ||
+ (interval > 1 && calcMode == calc_discrete)) {
+ steps = 0;
+ if (cur_x.size () != end_x.size () ||
+ cur_y.size () != end_y.size ()) {
+ cur_x = end_x;
+ cur_y = end_y;
+ applyStep (); // we lost some steps ..
+ }
+ }
+ } else
+ anim_timer = 0;
+ AnimateGroupData::stopped ();
+}
+
+KDE_NO_EXPORT void AnimateMotionData::applyStep () {
+ Node *target = target_element.ptr ();
+ if (!checkTarget (target))
+ return;
+ if (SMIL::id_node_region == target->id) {
+ SMIL::Region* r = static_cast <SMIL::Region*> (target);
+ if (r->surface ()) {
+ r->sizes.move (cur_x, cur_y);
+ r->boundsUpdate ();
+ }
+ } else {
+ SMIL::MediaType *mt = static_cast <SMIL::MediaType *> (target);
+ if (mt->surface ()) {
+ mt->sizes.move (cur_x, cur_y);
+ mt->boundsUpdate ();
+ }
+ }
+}
+
+KDE_NO_EXPORT bool AnimateMotionData::timerTick () {
+ if (!anim_timer) {
+ kdError () << "spurious animateMotion timer tick" << endl;
+ } else if (cur_step++ < steps) {
+ switch (calcMode) {
+ case calc_paced: // FIXME
+ case calc_linear:
+ cur_x += delta_x;
+ cur_y += delta_y;
+ break;
+ case calc_spline: {
+ Point2D ps[4] = {
+ { 0, 0 },
+ { control_point[0], control_point[1] },
+ { control_point[2], control_point[3] },
+ { 1, 1 }
+ };
+ Point2D p = PointOnCubicBezier (ps, 1.0 * cur_step / steps);
+ cur_x = delta_x;
+ cur_y = delta_y;
+ cur_x *= p.y;
+ cur_y *= p.y;
+ cur_x += begin_x;
+ cur_y += begin_y;
+ break;
+ }
+ case calc_discrete:
+ return true; // very sub-optimal timer
+ }
+ applyStep ();
+ return true;
+ } else if (values.size () > ++interval + 1) {
+ getCoordinates (values[interval], begin_x, begin_y);
+ getCoordinates (values[interval+1], end_x, end_y);
+ if (setInterval ()) {
+ applyStep ();
+ return true;
+ }
+ }
+ anim_timer = NULL;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+
+static NodePtr findExternalTree (NodePtr mrl) {
+ for (NodePtr c = mrl->firstChild (); c; c = c->nextSibling ()) {
+ Mrl * m = c->mrl ();
+ if (m && m->opener == mrl)
+ return c;
+ }
+ return 0L;
+}
+
+KDE_NO_CDTOR_EXPORT MediaTypeRuntime::MediaTypeRuntime (NodePtr e)
+ : Runtime (e) {}
+
+KDE_NO_CDTOR_EXPORT MediaTypeRuntime::~MediaTypeRuntime () {
+ killWGet ();
+}
+
+/**
+ * re-implement for pending KIO::Job operations
+ */
+KDE_NO_EXPORT void KMPlayer::MediaTypeRuntime::reset () {
+ clear ();
+ postpone_lock = 0L;
+ Runtime::reset ();
+}
+
+/**
+ * will request a repaint of attached region
+ */
+KDE_NO_EXPORT void MediaTypeRuntime::stopped () {
+ clipStop ();
+ document_postponed = 0L;
+ Node * e = element.ptr ();
+ if (e) {
+ for (NodePtr n = e->firstChild (); n; n = n->nextSibling ())
+ if (n->unfinished ()) // finish child documents
+ n->finish ();
+ }
+ Runtime::stopped ();
+}
+
+KDE_NO_EXPORT void MediaTypeRuntime::clipStart () {
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ SMIL::RegionBase *r =mt ? convertNode<SMIL::RegionBase>(mt->region_node):0L;
+ if (r && r->surface ())
+ for (NodePtr n = mt->firstChild (); n; n = n->nextSibling ())
+ if ((n->mrl () && n->mrl ()->opener.ptr () == mt) ||
+ n->id == SMIL::id_node_smil ||
+ n->id == RP::id_node_imfl) {
+ n->activate ();
+ break;
+ }
+}
+
+KDE_NO_EXPORT void MediaTypeRuntime::clipStop () {
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (mt) {
+ mt->resetSurface ();
+ if (mt->external_tree && mt->external_tree->active ())
+ mt->external_tree->deactivate ();
+ }
+}
+
+KDE_NO_EXPORT void MediaTypeRuntime::postpone (bool) {
+}
+
+KDE_NO_CDTOR_EXPORT AudioVideoData::AudioVideoData (NodePtr e)
+ : MediaTypeRuntime (e) {}
+
+KDE_NO_EXPORT bool AudioVideoData::isAudioVideo () {
+ return timingstate == timings_started;
+}
+
+/**
+ * reimplement for request backend to play audio/video
+ */
+KDE_NO_EXPORT void AudioVideoData::started () {
+ if (element && !element->mrl ()->resolved) {
+ element->defer ();
+ return;
+ }
+ if (0 == durTime ().offset && dur_media == endTime ().durval)
+ durTime ().durval = dur_media; // duration of clip
+ MediaTypeRuntime::started ();
+}
+
+static void setSmilLinkNode (NodePtr n, NodePtr link) {
+ // this works only because we can only play one at a time FIXME
+ SMIL::Smil * s = SMIL::Smil::findSmilNode (n.ptr ());
+ if (s && (link || s->current_av_media_type == n)) // only reset ones own
+ s->current_av_media_type = link;
+}
+
+KDE_NO_EXPORT void AudioVideoData::clipStart () {
+ NodePtr element_protect = element; // note element is weak
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ PlayListNotify * n = mt ? mt->document ()->notify_listener : 0L;
+ //kdDebug() << "AudioVideoData::clipStart " << mt->resolved << endl;
+ if (n && mt->region_node && !mt->external_tree && !mt->src.isEmpty()) {
+ setSmilLinkNode (element, element);
+ mt->repeat = repeat_count == dur_infinite ? 9998 : repeat_count;
+ repeat_count = 0;
+ n->requestPlayURL (mt);
+ document_postponed = mt->document()->connectTo(mt, event_postponed);
+ }
+ MediaTypeRuntime::clipStart ();
+}
+
+KDE_NO_EXPORT void AudioVideoData::clipStop () {
+ if (durTime ().durval == dur_media)
+ durTime ().durval = dur_timer;//reset to make this finish
+ MediaTypeRuntime::clipStop ();
+ setSmilLinkNode (element, 0L);
+}
+
+KDE_NO_EXPORT
+bool AudioVideoData::parseParam(const TrieString &name, const QString &val) {
+ //kdDebug () << "AudioVideoData::parseParam " << name << "=" << val << endl;
+ if (name == StringPool::attr_src) {
+ NodePtr element_protect = element; // note element is weak
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (mt) {
+ if (!mt->resolved || mt->src != val) {
+ if (mt->external_tree)
+ mt->removeChild (mt->external_tree);
+ mt->src = val;
+ mt->resolved = mt->document ()->notify_listener->resolveURL (element);
+ }
+ if (timingstate == timings_started && mt->resolved)
+ clipStart ();
+ }
+ } else
+ return MediaTypeRuntime::parseParam (name, val);
+ return true;
+}
+
+KDE_NO_EXPORT void AudioVideoData::postpone (bool b) {
+ kdDebug () << "AudioVideoData::postpone " << b << endl;
+ if (element->unfinished () && b)
+ element->setState (Node::state_deferred);
+ else if (element->state == Node::state_deferred && !b)
+ element->setState (Node::state_began);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT MouseListeners::MouseListeners () :
+ m_ActionListeners (new NodeRefList),
+ m_OutOfBoundsListeners (new NodeRefList),
+ m_InBoundsListeners (new NodeRefList) {}
+
+NodeRefListPtr MouseListeners::listeners (unsigned int eid) {
+ switch (eid) {
+ case event_activated:
+ return m_ActionListeners;
+ case event_inbounds:
+ return m_InBoundsListeners;
+ case event_outbounds:
+ return m_OutOfBoundsListeners;
+ }
+ return 0L;
+}
+
+//-----------------------------------------------------------------------------
+
+static Element * fromScheduleGroup (NodePtr & d, const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "par"))
+ return new SMIL::Par (d);
+ else if (!strcmp (ctag, "seq"))
+ return new SMIL::Seq (d);
+ else if (!strcmp (ctag, "excl"))
+ return new SMIL::Excl (d);
+ return 0L;
+}
+
+static Element * fromParamGroup (NodePtr & d, const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "param"))
+ return new SMIL::Param (d);
+ else if (!strcmp (ctag, "area") || !strcmp (ctag, "anchor"))
+ return new SMIL::Area (d, tag);
+ return 0L;
+}
+
+static Element * fromAnimateGroup (NodePtr & d, const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "set"))
+ return new SMIL::Set (d);
+ else if (!strcmp (ctag, "animate"))
+ return new SMIL::Animate (d);
+ else if (!strcmp (ctag, "animateMotion"))
+ return new SMIL::AnimateMotion (d);
+ return 0L;
+}
+
+static Element * fromMediaContentGroup (NodePtr & d, const QString & tag) {
+ const char * taglatin = tag.latin1 ();
+ if (!strcmp (taglatin, "video") || !strcmp (taglatin, "audio"))
+ return new SMIL::AVMediaType (d, tag);
+ else if (!strcmp (taglatin, "img"))
+ return new SMIL::ImageMediaType (d);
+ else if (!strcmp (taglatin, "text"))
+ return new SMIL::TextMediaType (d);
+ else if (!strcmp (taglatin, "ref"))
+ return new SMIL::RefMediaType (d);
+ else if (!strcmp (taglatin, "brush"))
+ return new SMIL::Brush (d);
+ else if (!strcmp (taglatin, "a"))
+ return new SMIL::Anchor (d);
+ // animation, textstream
+ return 0L;
+}
+
+static Element * fromContentControlGroup (NodePtr & d, const QString & tag) {
+ if (!strcmp (tag.latin1 (), "switch"))
+ return new SMIL::Switch (d);
+ return 0L;
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT NodePtr SMIL::Smil::childFromTag (const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "body"))
+ return new SMIL::Body (m_doc);
+ else if (!strcmp (ctag, "head"))
+ return new SMIL::Head (m_doc);
+ return NodePtr ();
+}
+
+KDE_NO_EXPORT void SMIL::Smil::activate () {
+ //kdDebug () << "Smil::activate" << endl;
+ current_av_media_type = NodePtr ();
+ resolved = true;
+ SMIL::Layout * layout = convertNode <SMIL::Layout> (layout_node);
+ if (layout && layout->region_surface) {
+ kdError() << "Layout already has a surface" << endl;
+ }
+ if (layout)
+ Element::activate ();
+ else
+ Element::deactivate(); // some unfortunate reset in parent doc
+}
+
+KDE_NO_EXPORT void SMIL::Smil::deactivate () {
+ if (layout_node)
+ convertNode <SMIL::Layout> (layout_node)->repaint ();
+ if (layout_node)
+ convertNode <SMIL::Layout> (layout_node)->region_surface = NULL;
+ Mrl::getSurface(0L);
+ Mrl::deactivate ();
+}
+
+KDE_NO_EXPORT bool SMIL::Smil::handleEvent (EventPtr event) {
+ return layout_node ? layout_node->handleEvent (event) : false;
+}
+
+KDE_NO_EXPORT void SMIL::Smil::closed () {
+ NodePtr head;
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->id == id_node_head) {
+ head = e;
+ break;
+ }
+ if (!head) {
+ SMIL::Head * h = new SMIL::Head (m_doc);
+ insertBefore (h, firstChild ());
+ h->setAuxiliaryNode (true);
+ h->closed ();
+ head = h;
+ }
+ for (NodePtr e = head->firstChild (); e; e = e->nextSibling ()) {
+ if (e->id == id_node_layout) {
+ layout_node = e;
+ } else if (e->id == id_node_title) {
+ QString str = e->innerText ();
+ pretty_name = str.left (str.find (QChar ('\n')));
+ } else if (e->id == id_node_meta) {
+ Element * elm = convertNode <Element> (e);
+ const QString name = elm->getAttribute (StringPool::attr_name);
+ if (name == QString::fromLatin1 ("title"))
+ pretty_name = elm->getAttribute ("content");
+ else if (name == QString::fromLatin1 ("base"))
+ src = elm->getAttribute ("content");
+ }
+ }
+ if (!layout_node) {
+ kdError () << "no <root-layout>" << endl;
+ return;
+ }
+}
+
+KDE_NO_EXPORT void SMIL::Smil::childDone (NodePtr child) {
+ if (unfinished ()) {
+ if (child->nextSibling ())
+ child->nextSibling ()->activate ();
+ else {
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->active ())
+ e->deactivate ();
+ finish ();
+ }
+ }
+}
+
+KDE_NO_EXPORT Mrl * SMIL::Smil::linkNode () {
+ return current_av_media_type ? current_av_media_type->mrl () : this;
+}
+
+KDE_NO_EXPORT bool SMIL::Smil::expose () const {
+ return !pretty_name.isEmpty () || //return false if no title and only one
+ previousSibling () || nextSibling ();
+}
+
+KDE_NO_EXPORT void SMIL::Smil::accept (Visitor * v) {
+ if (active () && layout_node)
+ layout_node->accept( v );
+}
+
+void SMIL::Smil::jump (const QString & id) {
+ NodePtr n = document ()->getElementById (this, id, false);
+ if (n) {
+ if (n->unfinished ())
+ kdDebug() << "Smil::jump node is unfinished " << id << endl;
+ else {
+ for (NodePtr p = n; p; p = p->parentNode ()) {
+ if (p->unfinished () &&
+ p->id >= id_node_first_group &&
+ p->id <= id_node_last_group) {
+ convertNode <GroupBase> (p)->setJumpNode (n);
+ break;
+ }
+ if (n->id == id_node_body || n->id == id_node_smil) {
+ kdError() << "Smil::jump node passed body for " <<id<< endl;
+ break;
+ }
+ }
+ }
+ }
+}
+
+SMIL::Smil * SMIL::Smil::findSmilNode (Node * node) {
+ for (Node * e = node; e; e = e->parentNode ().ptr ())
+ if (e->id == SMIL::id_node_smil)
+ return static_cast <SMIL::Smil *> (e);
+ return 0L;
+}
+
+//-----------------------------------------------------------------------------
+
+static void headChildDone (NodePtr node, NodePtr child) {
+ if (node->unfinished ()) {
+ if (child->nextSibling ())
+ child->nextSibling ()->activate ();
+ else
+ node->finish (); // we're done
+ }
+}
+
+KDE_NO_EXPORT NodePtr SMIL::Head::childFromTag (const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "layout"))
+ return new SMIL::Layout (m_doc);
+ else if (!strcmp (ctag, "title"))
+ return new DarkNode (m_doc, tag, id_node_title);
+ else if (!strcmp (ctag, "meta"))
+ return new DarkNode (m_doc, tag, id_node_meta);
+ else if (!strcmp (ctag, "transition"))
+ return new SMIL::Transition (m_doc);
+ return NodePtr ();
+}
+
+KDE_NO_EXPORT bool SMIL::Head::expose () const {
+ return false;
+}
+
+KDE_NO_EXPORT void SMIL::Head::closed () {
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->id == id_node_layout)
+ return;
+ SMIL::Layout * layout = new SMIL::Layout (m_doc);
+ appendChild (layout);
+ layout->setAuxiliaryNode (true);
+ layout->closed (); // add root-layout and a region
+}
+
+KDE_NO_EXPORT void SMIL::Head::childDone (NodePtr child) {
+ headChildDone (this, child);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::Layout::Layout (NodePtr & d)
+ : RegionBase (d, id_node_layout) {}
+
+KDE_NO_EXPORT NodePtr SMIL::Layout::childFromTag (const QString & tag) {
+ const char * ctag = tag.ascii ();
+ if (!strcmp (ctag, "root-layout")) {
+ NodePtr e = new SMIL::RootLayout (m_doc);
+ rootLayout = e;
+ return e;
+ } else if (!strcmp (ctag, "region"))
+ return new SMIL::Region (m_doc);
+ else if (!strcmp (ctag, "regPoint"))
+ return new SMIL::RegPoint (m_doc);
+ return NodePtr ();
+}
+
+KDE_NO_EXPORT void SMIL::Layout::closed () {
+ SMIL::RegionBase * rl = convertNode <SMIL::RootLayout> (rootLayout);
+ bool has_root (rl);
+ if (!has_root) { // just add one if none there
+ rl = new SMIL::RootLayout (m_doc);
+ NodePtr sr = rl; // protect against destruction
+ rl->setAuxiliaryNode (true);
+ rootLayout = rl;
+ int w_root =0, h_root = 0, reg_count = 0;
+ for (NodePtr n = firstChild (); n; n = n->nextSibling ()) {
+ if (n->id == id_node_region) {
+ SMIL::Region * rb =convertNode <SMIL::Region> (n);
+ rb->init ();
+ rb->calculateBounds (0, 0);
+ if (int (rb->x + rb->w) > w_root)
+ w_root = rb->x + rb->w;
+ if (int (rb->y + rb->h) > h_root)
+ h_root = rb->y + rb->h;
+ reg_count++;
+ }
+ }
+ if (!reg_count) {
+ w_root = 320; h_root = 240; // have something to start with
+ SMIL::Region * r = new SMIL::Region (m_doc);
+ appendChild (r);
+ r->setAuxiliaryNode (true);
+ }
+ rl->setAttribute(StringPool::attr_width, QString::number(w_root));
+ rl->setAttribute(StringPool::attr_height,QString::number(h_root));
+ insertBefore (sr, firstChild ());
+ } else {
+ if (childNodes ()->length () < 2) { // only a root-layout
+ SMIL::Region * r = new SMIL::Region (m_doc);
+ appendChild (r);
+ r->setAuxiliaryNode (true);
+ }
+ Smil *s = Smil::findSmilNode (this);
+ if (s) {
+ s->width = rl->getAttribute(StringPool::attr_width).toDouble ();
+ s->height = rl->getAttribute(StringPool::attr_height).toDouble();
+ }
+ }
+}
+
+KDE_NO_EXPORT void SMIL::Layout::activate () {
+ //kdDebug () << "SMIL::Layout::activate" << endl;
+ RegionBase::activate ();
+ if (surface ()) {
+ updateDimensions ();
+ repaint ();
+ }
+ finish (); // proceed and allow 'head' to finish
+}
+
+KDE_NO_EXPORT void SMIL::Layout::updateDimensions () {
+ RegionBase * rb = static_cast <RegionBase *> (rootLayout.ptr ());
+ x = y = 0;
+ w = rb->sizes.width.size ();
+ h = rb->sizes.height.size ();
+ //kdDebug () << "Layout::updateDimensions " << w << "," << h <<endl;
+ SMIL::RegionBase::updateDimensions ();
+}
+
+KDE_NO_EXPORT Surface *SMIL::Layout::surface () {
+ if (!region_surface) {
+ SMIL::Smil * s = Smil::findSmilNode (this);
+ if (s) {
+ SMIL::RegionBase *rl = convertNode <SMIL::RootLayout> (rootLayout);
+ region_surface = s->getSurface (s);
+ w = s->width;
+ h = s->height;
+ if (region_surface) {
+ SRect rect = region_surface->bounds;
+ if (rl && auxiliaryNode ()) {
+ w = rect.width ();
+ h = rect.height ();
+ rl->setAttribute (StringPool::attr_width, QString::number ((int)w));
+ rl->setAttribute (StringPool::attr_height, QString::number ((int)h));
+ rl->setParam (StringPool::attr_width, QString::number((int)w));
+ rl->setParam (StringPool::attr_height,QString::number((int)h));
+ } else if (region_surface && w > 0 && h > 0) {
+ updateDimensions ();
+ }
+ //kdDebug() << "Layout::surface bounds " << rect.width () << "x" << rect.height () << " w:" << w << " h:" << h << " xs:" << region_surface->xscale << " ys:" << region_surface->yscale << endl;
+ }
+ }
+ }
+ return region_surface.ptr ();
+}
+
+KDE_NO_EXPORT void SMIL::Layout::accept (Visitor * v) {
+ v->visit (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::RegionBase::RegionBase (NodePtr & d, short id)
+ : Element (d, id), x (0), y (0), w (0), h (0),
+ z_order (1), background_color (0)
+ {}
+
+KDE_NO_CDTOR_EXPORT SMIL::RegionBase::~RegionBase () {
+ if (region_surface)
+ region_surface->remove ();
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::activate () {
+ show_background = ShowAlways;
+ init ();
+ setState (state_activated);
+ for (NodePtr r = firstChild (); r; r = r->nextSibling ())
+ if (r->id == id_node_region || r->id == id_node_root_layout)
+ r->activate ();
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::childDone (NodePtr child) {
+ headChildDone (this, child);
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::deactivate () {
+ background_color = 0;
+ background_image.truncate (0);
+ if (region_surface)
+ region_surface->background_color = 0;
+ cached_img.setUrl (QString ());
+ postpone_lock = NULL;
+ killWGet ();
+ sizes.resetSizes ();
+ Element::deactivate ();
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::remoteReady (QByteArray & data) {
+ QImage *pix = new QImage (data);
+ if (!pix->isNull ()) {
+ cached_img.data->image = pix;
+ if (region_surface)
+ region_surface->remove (); // FIXME: only surface
+ } else {
+ delete pix;
+ }
+ postpone_lock = 0L;
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::repaint () {
+ if (surface ())
+ region_surface->repaint (SRect (0, 0, w, h));
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::repaint (const SRect & rect) {
+ if (surface ())
+ region_surface->repaint (SRect (0, 0, w, h).intersect (rect));
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::updateDimensions () {
+ if (surface () && active ())
+ for (NodePtr r = firstChild (); r; r = r->nextSibling ())
+ if (r->id == id_node_region) {
+ SMIL::Region * cr = static_cast <SMIL::Region *> (r.ptr ());
+ cr->calculateBounds (w, h);
+ cr->updateDimensions ();
+ }
+}
+
+KDE_NO_EXPORT void SMIL::RegionBase::boundsUpdate () {
+ // if there is a region_surface and it's moved, do a limit repaint
+ NodePtr p = parentNode ();
+ if (p && (p->id==SMIL::id_node_region || p->id==SMIL::id_node_layout) &&
+ region_surface) {
+ RegionBase *pr = convertNode <SMIL::RegionBase> (p);
+ SRect old_bounds = region_surface->bounds;
+ w = 0; h = 0;
+ sizes.calcSizes (this, pr->w, pr->h, x, y, w, h);
+ region_surface->bounds = SRect (x, y, w, h);
+ pr->repaint (region_surface->bounds.unite (old_bounds));
+ }
+}
+
+KDE_NO_EXPORT Surface *SMIL::RegionBase::surface () {
+ if (!region_surface) {
+ Node *n = parentNode ().ptr ();
+ if (n &&
+ (SMIL::id_node_region == n->id ||
+ SMIL::id_node_layout == n->id)) {
+ Surface *ps = static_cast <SMIL::Region *> (n)->surface ();
+ if (ps) {
+ region_surface = ps->createSurface (this, SRect (x, y, w, h));
+ region_surface->background_color = background_color;
+ }
+ }
+ }
+ return region_surface.ptr ();
+}
+
+KDE_NO_EXPORT
+void SMIL::RegionBase::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "RegionBase::parseParam " << getAttribute ("id") << " " << name << "=" << val << " active:" << active() << endl;
+ bool need_repaint = false;
+ SRect rect = SRect (x, y, w, h);
+ bool dim_changed;
+ if (name == "background-color" || name == "backgroundColor") {
+ if (val.isEmpty ())
+ background_color = 0;
+ else
+ background_color = 0xff000000 | QColor (val).rgb ();
+ if (region_surface || (active () && surface ()))
+ region_surface->background_color = background_color;
+ need_repaint = true;
+ } else if (name == "z-index") {
+ z_order = val.toInt ();
+ need_repaint = true;
+ } else if (sizes.setSizeParam (name, val, dim_changed)) {
+ if (active ()) {
+ if (region_surface) {
+ if (dim_changed) {
+ region_surface->remove ();
+ } else {
+ boundsUpdate ();
+ return; // smart update of old bounds to new moved one
+ }
+ }
+ NodePtr p = parentNode ();
+ if (p &&(p->id==SMIL::id_node_region ||p->id==SMIL::id_node_layout))
+ convertNode <SMIL::RegionBase> (p)->updateDimensions ();
+ rect = rect.unite (SRect (x, y, w, h));
+ need_repaint = true;
+ }
+ } else if (name == "showBackground") {
+ if (val == "whenActive")
+ show_background = ShowWhenActive;
+ else
+ show_background = ShowAlways;
+ need_repaint = true;
+ } else if (name == "backgroundImage") {
+ background_image = val;
+ Smil * s = SMIL::Smil::findSmilNode (this);
+ if (s) {
+ killWGet ();
+ need_repaint = !cached_img.isEmpty ();
+ Mrl *mrl = s->parentNode () ? s->parentNode ()->mrl () : NULL;
+ QString url = mrl ? KURL (mrl->absolutePath (), val).url () : val;
+ cached_img.setUrl (url);
+ if (cached_img.isEmpty ()) {
+ postpone_lock = document ()->postpone ();
+ wget (url);
+ } else {
+ need_repaint = true;
+ }
+ }
+ }
+ if (need_repaint && active () && surface() && region_surface->parentNode ())
+ region_surface->parentNode ()->repaint (rect);
+ Element::parseParam (name, val);
+}
+
+KDE_NO_CDTOR_EXPORT SMIL::Region::Region (NodePtr & d)
+ : RegionBase (d, id_node_region),
+ has_mouse (false),
+ m_AttachedMediaTypes (new NodeRefList) {}
+
+KDE_NO_EXPORT NodePtr SMIL::Region::childFromTag (const QString & tag) {
+ if (!strcmp (tag.latin1 (), "region"))
+ return new SMIL::Region (m_doc);
+ return NodePtr ();
+}
+
+/**
+ * calculates dimensions of this regions with _w and _h as width and height
+ * of parent Region (representing 100%)
+ */
+KDE_NO_EXPORT
+void SMIL::Region::calculateBounds (Single pw, Single ph) {
+ Single x1 (x), y1 (y), w1 (w), h1 (h);
+ sizes.calcSizes (this, pw, ph, x, y, w, h);
+ if (surface ())
+ region_surface->bounds = SRect (x, y, w, h);
+ //kdDebug () << "Region::calculateBounds parent:" << pw << "x" << ph << " this:" << x << "," << y << " " << w << "x" << h << endl;
+}
+
+NodeRefListPtr SMIL::Region::listeners (unsigned int eid) {
+ NodeRefListPtr l = mouse_listeners.listeners (eid);
+ if (l)
+ return l;
+ switch (eid) {
+ case mediatype_attached:
+ return m_AttachedMediaTypes;
+ }
+ return RegionBase::listeners (eid);
+}
+
+KDE_NO_EXPORT void SMIL::Region::accept (Visitor * v) {
+ v->visit (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT
+void SMIL::RegPoint::parseParam (const TrieString & p, const QString & v) {
+ bool b;
+ sizes.setSizeParam (p, v, b); // TODO: if dynamic, make sure to repaint
+ Element::parseParam (p, v);
+}
+
+//-----------------------------------------------------------------------------
+
+static struct TransTypeInfo {
+ const char *name;
+ SMIL::Transition::TransType type;
+ short sub_types;
+ SMIL::Transition::TransSubType sub_type[8];
+} transition_type_info[] = {
+#include "transitions.txt"
+};
+
+static struct SubTransTypeInfo {
+ const char *name;
+ SMIL::Transition::TransSubType sub_type;
+} sub_transition_type_info[] = {
+#include "subtrans.txt"
+};
+
+static TransTypeInfo *transInfoFromString (const char *t) {
+ // TODO binary search
+ for (int i = 0; transition_type_info[i].name; ++i)
+ if (!strcmp (t, transition_type_info[i].name))
+ return transition_type_info + i;
+ return NULL;
+}
+
+static
+SMIL::Transition::TransSubType subTransInfoFromString (const char *s) {
+ for (int i = 0; sub_transition_type_info[i].name; ++i)
+ if (!strcmp (s, sub_transition_type_info[i].name))
+ return sub_transition_type_info[i].sub_type;
+ return SMIL::Transition::SubTransTypeNone;
+}
+
+KDE_NO_CDTOR_EXPORT SMIL::Transition::Transition (NodePtr & d)
+ : Element (d, id_node_transition),
+ type_info (NULL), direction (dir_forward), dur (10), fade_color (0) {}
+
+KDE_NO_EXPORT void SMIL::Transition::activate () {
+ type = TransTypeNone;
+ sub_type = SubTransTypeNone;
+ start_progress = 0.0;
+ end_progress = 1.0;
+ type_info = NULL;
+ init ();
+ Element::activate ();
+}
+
+KDE_NO_EXPORT
+void SMIL::Transition::parseParam (const TrieString & para, const QString & val) {
+ if (para == StringPool::attr_type) {
+ type_info = transInfoFromString (val.ascii ());
+ if (type_info) {
+ type = type_info->type;
+ if (SubTransTypeNone != sub_type) {
+ for (int i = 0; i < type_info->sub_types; ++i)
+ if (type_info->sub_type[i] == sub_type)
+ return;
+ }
+ if (type_info->sub_types > 0)
+ sub_type = type_info->sub_type[0];
+ }
+ } else if (para == StringPool::attr_dur) {
+ parseTime (val, dur);
+ } else if (para == "subtype") {
+ sub_type = subTransInfoFromString (val.ascii ());
+ if (type_info) {
+ if (SubTransTypeNone != sub_type) {
+ for (int i = 0; i < type_info->sub_types; ++i)
+ if (type_info->sub_type[i] == sub_type)
+ return;
+ }
+ if (type_info->sub_types > 0)
+ sub_type = type_info->sub_type[0];
+ }
+ } else if (para == "fadeColor") {
+ fade_color = QColor (getAttribute (val)).rgb ();
+ } else if (para == "direction") {
+ direction = val == "reverse" ? dir_reverse : dir_forward;
+ } else if (para == "startProgress") {
+ start_progress = val.toDouble();
+ if (start_progress < 0.0)
+ start_progress = 0.0;
+ else if (start_progress > 1.0)
+ start_progress = 1.0;
+ } else if (para == "endProgress") {
+ end_progress = val.toDouble();
+ if (end_progress < start_progress)
+ end_progress = start_progress;
+ else if (end_progress > 1.0)
+ end_progress = 1.0;
+ } else {
+ Element::parseParam (para, val);
+ }
+}
+
+KDE_NO_EXPORT bool SMIL::Transition::supported () {
+ switch (type) {
+ case Fade:
+ case BarWipe:
+ case BowTieWipe:
+ case PushWipe:
+ case IrisWipe:
+ case ClockWipe:
+ case EllipseWipe:
+ return true;
+ default:
+ return false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::TimedMrl::TimedMrl (NodePtr & d, short id)
+ : Mrl (d, id),
+ fill_active (fill_auto),
+ m_StartListeners (new NodeRefList),
+ m_StartedListeners (new NodeRefList),
+ m_StoppedListeners (new NodeRefList),
+ m_runtime (0L) {}
+
+KDE_NO_CDTOR_EXPORT SMIL::TimedMrl::~TimedMrl () {
+ delete m_runtime;
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::closed () {
+ pretty_name = getAttribute (StringPool::attr_title);
+ Mrl::closed ();
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::init () {
+ runtime ()->reset ();
+ begin_time = finish_time = 0;
+ fill = fill_default;
+ fill_def = fill_inherit;
+ fill_active = getDefaultFill (this);
+ Mrl::init ();
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::activate () {
+ //kdDebug () << "SMIL::TimedMrl(" << nodeName() << ")::activate" << endl;
+ Runtime * rt = runtime ();
+ init ();
+ setState (state_activated);
+ if (rt == m_runtime) // Runtime might already be dead
+ rt->begin ();
+ else
+ deactivate ();
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::begin () {
+ begin_time = document ()->last_event_time;
+ Element::begin ();
+ runtime ()->propagateStop (false); //see whether this node has a livetime or not
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::deactivate () {
+ //kdDebug () << "SMIL::TimedMrl(" << nodeName() << ")::deactivate" << endl;
+ if (unfinished ())
+ finish ();
+ if (m_runtime) {
+ m_runtime->reset ();
+ delete m_runtime;
+ m_runtime = 0L;
+ }
+ Mrl::deactivate ();
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::finish () {
+ if (m_runtime &&
+ (m_runtime->state () == Runtime::timings_started ||
+ m_runtime->state () == Runtime::timings_began)) {
+ runtime ()->propagateStop (true); // reschedule through Runtime::stopped
+ } else {
+ finish_time = document ()->last_event_time;
+ Mrl::finish ();
+ propagateEvent (new Event (event_stopped));
+ }
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::reset () {
+ //kdDebug () << "SMIL::TimedMrl::reset " << endl;
+ Mrl::reset ();
+ delete m_runtime;
+ m_runtime = 0L;
+}
+
+KDE_NO_EXPORT void SMIL::TimedMrl::childBegan (NodePtr) {
+ if (state != state_began)
+ begin ();
+}
+
+/*
+ * Re-implement, but keeping sequential behaviour.
+ * Bail out if Runtime is running. In case of dur_media, give Runtime
+ * a hand with calling propagateStop(true)
+ */
+KDE_NO_EXPORT void SMIL::TimedMrl::childDone (NodePtr c) {
+ if (!active ())
+ return; // forced reset
+ if (c->nextSibling ())
+ c->nextSibling ()->activate ();
+ else { // check if Runtime still running
+ Runtime * tr = runtime ();
+ if (tr->state () < Runtime::timings_stopped) {
+ if (tr->state () == Runtime::timings_started)
+ tr->propagateStop (false);
+ return; // still running, wait for runtime to finish
+ }
+ finish ();
+ }
+}
+
+KDE_NO_EXPORT NodeRefListPtr SMIL::TimedMrl::listeners (unsigned int id) {
+ if (id == event_stopped)
+ return m_StoppedListeners;
+ else if (id == event_started)
+ return m_StartedListeners;
+ else if (id == event_to_be_started)
+ return m_StartListeners;
+ kdWarning () << "unknown event requested" << endl;
+ return NodeRefListPtr ();
+}
+
+KDE_NO_EXPORT bool SMIL::TimedMrl::handleEvent (EventPtr event) {
+ int id = event->id ();
+ switch (id) {
+ case event_timer: {
+ TimerEvent * te = static_cast <TimerEvent *> (event.ptr ());
+ if (te && te->timer_info) {
+ if (te->timer_info->event_id == started_timer_id)
+ runtime ()->started ();
+ else if (te->timer_info->event_id == stopped_timer_id)
+ runtime ()->stopped ();
+ else if (te->timer_info->event_id == start_timer_id)
+ runtime ()->propagateStart ();
+ else if (te->timer_info->event_id == dur_timer_id)
+ runtime ()->propagateStop (true);
+ else
+ kdWarning () << "unhandled timer event" << endl;
+ }
+ break;
+ }
+ default:
+ if (m_runtime)
+ m_runtime->processEvent (id);
+ }
+ return true;
+}
+
+KDE_NO_EXPORT Runtime * SMIL::TimedMrl::getNewRuntime () {
+ return new Runtime (this);
+}
+
+KDE_NO_EXPORT
+void SMIL::TimedMrl::parseParam (const TrieString &para, const QString &value) {
+ if (para.startsWith (StringPool::attr_fill)) {
+ Fill * f = &fill;
+ if (para != StringPool::attr_fill) {
+ f = &fill_def;
+ *f = fill_inherit;
+ } else
+ *f = fill_default;
+ fill_active = fill_auto;
+ if (value == "freeze")
+ *f = fill_freeze;
+ else if (value == "hold")
+ *f = fill_hold;
+ else if (value == "auto")
+ *f = fill_auto;
+ else if (value == "remove")
+ *f = fill_remove;
+ else if (value == "transition")
+ *f = fill_transition;
+ if (fill == fill_default) {
+ if (fill_def == fill_inherit)
+ fill_active = getDefaultFill (this);
+ else
+ fill_active = fill_def;
+ } else
+ fill_active = fill;
+ } else if (!runtime ()->parseParam (para, value)) {
+ if (para == StringPool::attr_src) //block Mrl src parsing for now
+ kdDebug() << "parseParam src on " << nodeName() << endl;
+ else
+ Mrl::parseParam (para, value);
+ }
+}
+
+KDE_NO_EXPORT
+Runtime::DurationItem * SMIL::TimedMrl::getDuration (NodePtr n) {
+ if (!isTimedMrl (n) || !n->active ())
+ return 0L;
+ TimedMrl * tm = convertNode <SMIL::TimedMrl> (n);
+ return &tm->runtime ()->durations [Runtime::duration_time];
+}
+
+KDE_NO_EXPORT bool SMIL::TimedMrl::keepContent (Node *n) {
+ if (isTimedMrl (n)) {
+ TimedMrl * tm = convertNode <SMIL::TimedMrl> (n);
+ if (tm->runtime ()->timingstate == Runtime::timings_started)
+ return true;
+ Node *p = n->parentNode ();
+ Node *np = tm;
+ while (p && id_node_body != p->id && !isTimedMrl (p)) {
+ np = p;
+ p = p->parentNode ().ptr (); // skip anchors
+ }
+ if (tm->m_runtime && p && p->active ()) {
+ if (tm->runtime ()->timingstate == Runtime::timings_stopped)
+ switch (tm->fill_active) {
+ case fill_hold: // keep while parent active
+ return true;
+ case fill_freeze: // keep in parent duration
+ if (p->unfinished() &&
+ (p->id == SMIL::id_node_par ||
+ p->id == SMIL::id_node_excl ||
+ p->id == SMIL::id_node_switch ||
+ p->lastChild().ptr () == np))
+ return true;
+ // else fall through
+ case fill_default: // as freeze when no duration is set
+ case fill_auto: // or when parent finished w/o duration
+ return keepContent (p) &&
+ (p->id == SMIL::id_node_par ||
+ p->id == SMIL::id_node_excl ||
+ p->id == SMIL::id_node_switch ||
+ p->lastChild().ptr () == np) &&
+ tm->runtime ()->durTime ().durval == Runtime::dur_timer &&
+ !tm->runtime ()->durTime ().offset;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+KDE_NO_EXPORT SMIL::TimedMrl::Fill SMIL::TimedMrl::getDefaultFill (NodePtr n) {
+ for (NodePtr p = n->parentNode (); p; p = p->parentNode ())
+ if (isTimedMrl (p)) {
+ SMIL::TimedMrl * tm = convertNode<SMIL::TimedMrl>(p);
+ if (tm->fill_def != fill_inherit)
+ return tm->fill_def;
+ else if (tm->fill == fill_default)
+ return tm->fill_active; // assume parent figured out this
+ } else if (p->id == SMIL::id_node_smil)
+ break;
+ return fill_auto;
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT NodePtr SMIL::GroupBase::childFromTag (const QString & tag) {
+ Element * elm = fromScheduleGroup (m_doc, tag);
+ if (!elm) elm = fromMediaContentGroup (m_doc, tag);
+ if (!elm) elm = fromContentControlGroup (m_doc, tag);
+ if (!elm) elm = fromAnimateGroup (m_doc, tag);
+ if (elm)
+ return elm;
+ return NULL;
+}
+
+KDE_NO_EXPORT void SMIL::GroupBase::finish () {
+ setState (state_finished); // avoid recurstion through childDone
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (keepContent (e)) {
+ if (e->unfinished ())
+ e->finish ();
+ } else if (e->active ())
+ e->deactivate ();
+ TimedMrl::finish ();
+}
+
+KDE_NO_EXPORT void SMIL::GroupBase::deactivate () {
+ setState (state_deactivated); // avoid recurstion through childDone
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->active ())
+ e->deactivate ();
+ TimedMrl::deactivate ();
+}
+
+KDE_NO_EXPORT void SMIL::GroupBase::setJumpNode (NodePtr n) {
+ NodePtr child = n;
+ if (state > state_init) {
+ for (NodePtr c = firstChild (); c; c = c->nextSibling ())
+ if (c->active ())
+ c->reset ();
+ for (NodePtr c = n->parentNode (); c; c = c->parentNode ()) {
+ if (c.ptr () == this || c->id == id_node_body)
+ break;
+ if (c->id >= id_node_first_group && c->id <= id_node_last_group)
+ convertNode <GroupBase> (c)->jump_node = child;
+ child = c;
+ }
+ }
+ jump_node = child;
+ state = state_activated;
+ init ();
+ runtime()->beginAndStart (); // undefer through begin()
+}
+
+//-----------------------------------------------------------------------------
+
+// SMIL::Body was here
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void SMIL::Par::begin () {
+ jump_node = 0L; // TODO: adjust timings
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ e->activate ();
+ GroupBase::begin ();
+}
+
+KDE_NO_EXPORT void SMIL::Par::reset () {
+ GroupBase::reset ();
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ e->reset ();
+}
+
+KDE_NO_EXPORT void SMIL::Par::childDone (NodePtr) {
+ if (unfinished ()) {
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ()) {
+ if (e->unfinished ())
+ return; // not all finished
+ }
+ Runtime * tr = runtime ();
+ if (tr->state () == Runtime::timings_started) {
+ Runtime::Duration dv = tr->durTime ().durval;
+ if ((dv == Runtime::dur_timer && !tr->durTime ().offset)
+ || dv == Runtime::dur_media)
+ tr->propagateStop (false);
+ return; // still running, wait for runtime to finish
+ }
+ finish (); // we're done
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void SMIL::Seq::begin () {
+ if (jump_node) {
+ for (NodePtr c = firstChild (); c; c = c->nextSibling ())
+ if (c == jump_node) {
+ jump_node = 0L;
+ c->activate ();
+ break;
+ } else {
+ c->state = state_activated; // TODO: ..
+ if (c->isElementNode ())
+ convertNode <Element> (c)->init ();
+ c->state = state_finished; // TODO: ..
+ }
+ } else if (firstChild ())
+ firstChild ()->activate ();
+ GroupBase::begin ();
+}
+
+KDE_NO_EXPORT void SMIL::Seq::childDone (NodePtr child) {
+ if (unfinished ()) {
+ if (state != state_deferred) {
+ if (!keepContent (child) && child->active ())
+ child->deactivate ();
+ if (child->nextSibling ())
+ child->nextSibling ()->activate ();
+ else
+ finish ();
+ } else if (jump_node)
+ finish ();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void SMIL::Excl::begin () {
+ //kdDebug () << "SMIL::Excl::begin" << endl;
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ e->activate ();
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (isTimedMrl (e)) {
+ SMIL::TimedMrl * tm = static_cast <SMIL::TimedMrl *> (e.ptr ());
+ if (tm) { // make aboutToStart connection with TimedMrl children
+ ConnectionPtr c = tm->connectTo (this, event_to_be_started);
+ started_event_list.append (new ConnectionStoreItem (c));
+ }
+ }
+ GroupBase::begin ();
+}
+
+KDE_NO_EXPORT void SMIL::Excl::deactivate () {
+ started_event_list.clear (); // auto disconnect on destruction of data items
+ GroupBase::deactivate ();
+}
+
+KDE_NO_EXPORT void SMIL::Excl::childDone (NodePtr /*child*/) {
+ // first check if somenode has taken over
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (isTimedMrl (e)) {
+ Runtime *tr = convertNode <SMIL::TimedMrl> (e)->runtime();
+ if (tr->state () == Runtime::timings_started)
+ return;
+ }
+ // now finish unless 'dur="indefinite/some event/.."'
+ Runtime * tr = runtime ();
+ if (tr->state () == Runtime::timings_started)
+ tr->propagateStop (false); // still running, wait for runtime to finish
+ else
+ finish (); // we're done
+}
+
+KDE_NO_EXPORT bool SMIL::Excl::handleEvent (EventPtr event) {
+ if (event->id () == event_to_be_started) {
+ ToBeStartedEvent * se = static_cast <ToBeStartedEvent *> (event.ptr ());
+ //kdDebug () << "Excl::handleEvent " << se->node->nodeName()<<endl;
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ()) {
+ if (e == se->node) // stop all _other_ child elements
+ continue;
+ if (!isTimedMrl (e))
+ continue; // definitely a stowaway
+ convertNode<SMIL::TimedMrl>(e)->runtime()->propagateStop(true);
+ }
+ return true;
+ } else
+ return TimedMrl::handleEvent (event);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void SMIL::Switch::begin () {
+ //kdDebug () << "SMIL::Switch::activate" << endl;
+ PlayListNotify * n = document()->notify_listener;
+ int pref = 0, max = 0x7fffffff, currate = 0;
+ if (n)
+ n->bitRates (pref, max);
+ if (firstChild ()) {
+ NodePtr fallback;
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->isElementNode ()) {
+ Element *elm = convertNode <Element> (e);
+ QString lang = elm->getAttribute ("systemLanguage");
+ if (!lang.isEmpty ()) {
+ lang = lang.replace (QChar ('-'), QChar ('_'));
+ char *clang = getenv ("LANG");
+ if (!clang) {
+ if (!fallback)
+ fallback = e;
+ } else if (QString (clang).lower ().startsWith (lang)) {
+ chosenOne = e;
+ } else if (!fallback) {
+ fallback = e->nextSibling ();
+ }
+ }
+ if (e->id == id_node_audio_video) {
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (e);
+ if (!chosenOne) {
+ chosenOne = e;
+ currate = mt->bitrate;
+ } else if (int (mt->bitrate) <= max) {
+ int delta1 = pref > currate ? pref-currate : currate-pref;
+ int delta2 = pref > int (mt->bitrate) ? pref-mt->bitrate : mt->bitrate-pref;
+ if (delta2 < delta1) {
+ chosenOne = e;
+ currate = mt->bitrate;
+ }
+ }
+ } else if (!fallback && e->isPlayable ())
+ fallback = e;
+ }
+ if (!chosenOne)
+ chosenOne = (fallback ? fallback : firstChild ());
+ chosenOne->activate ();
+ }
+ GroupBase::begin ();
+}
+
+KDE_NO_EXPORT void SMIL::Switch::deactivate () {
+ Element::deactivate ();
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ())
+ if (e->active ()) {
+ e->deactivate ();
+ break; // deactivate only the one running
+ }
+}
+
+KDE_NO_EXPORT void SMIL::Switch::reset () {
+ Element::reset ();
+ for (NodePtr e = firstChild (); e; e = e->nextSibling ()) {
+ if (e->state != state_init)
+ e->reset ();
+ }
+}
+
+KDE_NO_EXPORT void SMIL::Switch::childDone (NodePtr child) {
+ if (child->state == state_finished)
+ child->deactivate ();
+ //kdDebug () << "SMIL::Switch::childDone" << endl;
+ finish (); // only one child can run
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::LinkingBase::LinkingBase (NodePtr & d, short id)
+ : Element(d, id), show (show_replace) {}
+
+KDE_NO_EXPORT void SMIL::LinkingBase::deactivate () {
+ mediatype_activated = 0L;
+ mediatype_attach = 0L;
+ Element::deactivate ();
+}
+
+KDE_NO_EXPORT
+void SMIL::LinkingBase::parseParam(const TrieString &para, const QString &val) {
+ if (para == StringPool::attr_href) {
+ href = val;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::Anchor::Anchor (NodePtr & d)
+ : LinkingBase (d, id_node_anchor) {}
+
+KDE_NO_EXPORT void SMIL::Anchor::activate () {
+ init ();
+ for (NodePtr c = firstChild(); c; c = c->nextSibling ())
+ if (c->id >=id_node_first_mediatype && c->id <=id_node_last_mediatype) {
+ mediatype_activated = c->connectTo (this, event_activated);
+ mediatype_attach = c->connectTo (this, mediatype_attached);
+ break;
+ }
+ Element::activate ();
+}
+
+KDE_NO_EXPORT void SMIL::Anchor::childDone (NodePtr child) {
+ if (unfinished ()) {
+ if (child->nextSibling ())
+ child->nextSibling ()->activate ();
+ else
+ finish ();
+ }
+}
+
+NodePtr SMIL::Anchor::childFromTag (const QString & tag) {
+ return fromMediaContentGroup (m_doc, tag);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::Area::Area (NodePtr & d, const QString & t)
+ : LinkingBase (d, id_node_area), coords (0L), nr_coords (0), tag (t) {}
+
+KDE_NO_CDTOR_EXPORT SMIL::Area::~Area () {
+ delete [] coords;
+}
+
+KDE_NO_EXPORT void SMIL::Area::activate () {
+ init ();
+ if (parentNode () &&
+ parentNode ()->id >= id_node_first_mediatype &&
+ parentNode ()->id <= id_node_last_mediatype) {
+ mediatype_activated = parentNode ()->connectTo (this, event_activated);
+ mediatype_attach = parentNode ()->connectTo (this, mediatype_attached);
+ }
+ Element::activate ();
+}
+
+KDE_NO_EXPORT
+void SMIL::Area::parseParam (const TrieString & para, const QString & val) {
+ if (para == "coords") {
+ delete [] coords;
+ QStringList clist = QStringList::split (QString (","), val);
+ nr_coords = clist.count ();
+ coords = new SizeType [nr_coords];
+ for (int i = 0; i < nr_coords; ++i)
+ coords[i] = clist[i];
+ } else
+ LinkingBase::parseParam (para, val);
+}
+
+KDE_NO_EXPORT NodeRefListPtr SMIL::Area::listeners (unsigned int id) {
+ NodeRefListPtr l = mouse_listeners.listeners (id);
+ if (l)
+ return l;
+ return Element::listeners (id);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::MediaType::MediaType (NodePtr &d, const QString &t, short id)
+ : TimedMrl (d, id), m_type (t), bitrate (0), trans_step (0), trans_steps (0),
+ sensitivity (sens_opaque), trans_out_active (false),
+ m_MediaAttached (new NodeRefList) {
+ view_mode = Mrl::WindowMode;
+}
+
+KDE_NO_EXPORT NodePtr SMIL::MediaType::childFromTag (const QString & tag) {
+ Element * elm = fromContentControlGroup (m_doc, tag);
+ if (!elm) elm = fromParamGroup (m_doc, tag);
+ if (!elm) elm = fromAnimateGroup (m_doc, tag);
+ if (elm)
+ return elm;
+ return 0L;
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::closed () {
+ external_tree = findExternalTree (this);
+ Mrl *mrl = external_tree ? external_tree->mrl () : NULL;
+ if (mrl) {
+ width = mrl->width;
+ height = mrl->height;
+ }
+ TimedMrl::closed ();
+}
+
+KDE_NO_EXPORT
+void SMIL::MediaType::parseParam (const TrieString &para, const QString & val) {
+ bool update_surface = true;
+ if (para == "fit") {
+ const char * cval = val.ascii ();
+ if (!cval)
+ fit = fit_hidden;
+ else if (!strcmp (cval, "fill"))
+ fit = fit_fill;
+ else if (!strcmp (cval, "hidden"))
+ fit = fit_hidden;
+ else if (!strcmp (cval, "meet"))
+ fit = fit_meet;
+ else if (!strcmp (cval, "scroll"))
+ fit = fit_scroll;
+ else if (!strcmp (cval, "slice"))
+ fit = fit_slice;
+ else
+ fit = fit_hidden;
+ } else if (para == "rn:mediaOpacity") {
+ opacity = (int) SizeType (val).size (100);
+ } else if (para == "system-bitrate") {
+ bitrate = val.toInt ();
+ } else if (para == StringPool::attr_type) {
+ mimetype = val;
+ } else if (para == "transIn") {
+ trans_in = findTransition (this, val);
+ if (!trans_in)
+ kdWarning() << "Transition " << val << " not found in head" << endl;
+ } else if (para == "transOut") {
+ trans_out = findTransition (this, val);
+ if (!trans_out)
+ kdWarning() << "Transition " << val << " not found in head" << endl;
+ } else if (para == "sensitivity") {
+ if (val == "transparent")
+ sensitivity = sens_transparent;
+ //else if (val == "percentage") // TODO
+ // sensitivity = sens_percentage;
+ else
+ sensitivity = sens_opaque;
+ } else if (sizes.setSizeParam (para, val, update_surface)) {
+ if (!update_surface && fit_hidden == fit &&
+ sub_surface
+#ifdef HAVE_CAIRO
+ && sub_surface->surface
+#endif
+ ) {
+ boundsUpdate ();
+ return; // preserved surface by recalculationg sub_surface top-left
+ }
+ } else {
+ TimedMrl::parseParam (para, val);
+ }
+ if (sub_surface)
+ sub_surface->repaint ();
+ resetSurface ();
+ if (surface ())
+ sub_surface->repaint ();
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::boundsUpdate () {
+ SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
+ if (rb && sub_surface) {
+ SRect new_bounds = calculateBounds ();
+ SRect repaint_rect = sub_surface->bounds.unite (new_bounds);
+ sub_surface->bounds = new_bounds;
+ rb->repaint (repaint_rect);
+ }
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::activate () {
+ trans_out_active = false;
+ fit = fit_hidden;
+ opacity = 100;
+ init (); // sets all attributes
+ setState (state_activated);
+ for (NodePtr c = firstChild (); c; c = c->nextSibling ())
+ if (c != external_tree) {
+ // activate param/set/animate.. children
+ c->activate ();
+ break; // childDone will handle next siblings
+ }
+ runtime ()->begin ();
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::deactivate () {
+ region_paint = 0L;
+ region_mouse_enter = 0L;
+ region_mouse_leave = 0L;
+ region_mouse_click = 0L;
+ region_attach = 0L;
+ trans_step = trans_steps = 0;
+ if (region_node)
+ convertNode <SMIL::RegionBase> (region_node)->repaint ();
+ if (trans_timer)
+ document ()->cancelTimer (trans_timer);
+ if (trans_out_timer)
+ document ()->cancelTimer (trans_out_timer);
+ TimedMrl::deactivate (); // keep region for runtime rest
+ region_node = 0L;
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::begin () {
+ SMIL::Smil * s = Smil::findSmilNode (parentNode ().ptr ());
+ SMIL::Region * r = s ?
+ findRegion (s->layout_node, param (StringPool::attr_region)) : 0L;
+ MediaTypeRuntime *tr = static_cast<MediaTypeRuntime*>(runtime ());
+ if (trans_timer) // eg transOut and we're repeating
+ document ()->cancelTimer (trans_timer);
+ if (r) {
+ region_node = r;
+ region_mouse_enter = r->connectTo (this, event_inbounds);
+ region_mouse_leave = r->connectTo (this, event_outbounds);
+ region_mouse_click = r->connectTo (this, event_activated);
+ region_attach = r->connectTo (this, mediatype_attached);
+ r->repaint ();
+ tr->clipStart ();
+ Transition * trans = convertNode <Transition> (trans_in);
+ if (trans && trans->supported ()) {
+ active_trans = trans_in;
+ trans_step = 1;
+ if (Transition::Fade == trans->type) {
+ trans_steps = trans->dur;
+ trans_timer = document()->setTimeout(this, 100, trans_timer_id);
+ } else {
+ trans_steps = 4 * trans->dur;
+ trans_timer = document()->setTimeout(this, 25, trans_timer_id);
+ }
+ }
+ if (Runtime::dur_timer == tr->durTime().durval &&
+ tr->durTime().offset > 0) {
+ // FIXME: also account for fill duration
+ trans = convertNode <Transition> (trans_out);
+ if (trans && trans->supported () &&
+ (int) trans->dur < tr->durTime().offset)
+ trans_out_timer = document()->setTimeout (
+ this,
+ (tr->durTime().offset - trans->dur) * 100,
+ trans_out_timer_id);
+ }
+ } else
+ kdWarning () << nodeName() << "::begin " << src << " region '" <<
+ param (StringPool::attr_region) << "' not found" << endl;
+ TimedMrl::begin ();
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::finish () {
+ if (trans_timer && !keepContent (this)) {
+ document ()->cancelTimer (trans_timer);
+ ASSERT(!trans_timer);
+ }
+ if (region_node)
+ convertNode <SMIL::RegionBase> (region_node)->repaint ();
+ TimedMrl::finish ();
+ static_cast <MediaTypeRuntime *> (runtime ())->clipStop ();
+}
+
+/**
+ * Re-implement from TimedMrl, because we may have children like
+ * param/set/animatie that should all be activate, but also other smil or imfl
+ * documents, that should only be activated if the runtime has started
+ */
+KDE_NO_EXPORT void SMIL::MediaType::childDone (NodePtr child) {
+ bool child_doc = child->mrl () && child->mrl ()->opener.ptr () == this;
+ if (child_doc) {
+ child->deactivate (); // should only if fill not is freeze or hold
+ } else if (active ()) { // traverse param or area children
+ for (NodePtr c = child->nextSibling(); c; c = c->nextSibling ())
+ if (!c->mrl () || c->mrl ()->opener.ptr () != this ) {
+ c->activate ();
+ return;
+ }
+ Runtime * tr = runtime ();
+ if (tr->state () < Runtime::timings_stopped) {
+ if (tr->state () == Runtime::timings_started)
+ tr->propagateStop (child_doc); // what about repeat_count ..
+ return; // still running, wait for runtime to finish
+ }
+ }
+ if (active ())
+ finish ();
+}
+
+KDE_NO_EXPORT bool SMIL::MediaType::needsVideoWidget () {
+ MediaTypeRuntime * mtr = static_cast <MediaTypeRuntime *> (runtime ());
+ SMIL::Smil * s = SMIL::Smil::findSmilNode (this);
+ Node * link = s ? s->current_av_media_type.ptr () : 0L;
+ return ((link == this || !link) &&
+ (state == state_deferred || unfinished ()) && link &&
+ mtr->state () != Runtime::timings_stopped &&
+ (!strcmp (nodeName (), "video") || !strcmp (nodeName (), "ref")) &&
+ surface ());
+}
+
+SurfacePtr SMIL::MediaType::getSurface (NodePtr node) {
+ resetSurface ();
+ Surface *s = surface ();
+ if (s && node)
+ s->node = node;
+ return s;
+}
+
+KDE_NO_EXPORT Surface *SMIL::MediaType::surface () {
+ if (!keepContent (this)) {
+ resetSurface ();
+ return NULL;
+ }
+ if (!sub_surface) {
+ SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
+ if (rb && rb->surface ()) {
+ SRect rect = calculateBounds ();
+ sub_surface =rb->region_surface->createSurface (this, rect);
+ if (width > 0 && height > 0) {
+ sub_surface->xscale = 1.0 * rect.width () / width;
+ sub_surface->yscale = 1.0 * rect.height () / height;
+ }
+ //kdDebug() << sub_surface.ptr() << " " << nodeName() << " " << src << " " << rr.width() << "," << rr.height() << " => " << x << "," << y << w << "," << h << endl;
+ }
+ }
+ return sub_surface.ptr ();
+}
+
+KDE_NO_EXPORT void SMIL::MediaType::resetSurface () {
+ if (sub_surface)
+ sub_surface->remove ();
+ sub_surface = NULL;
+}
+
+KDE_NO_EXPORT SRect SMIL::MediaType::calculateBounds () {
+ SMIL::RegionBase *rb = convertNode <SMIL::RegionBase> (region_node);
+ if (rb && rb->surface ()) {
+ SRect rr = rb->region_surface->bounds;
+ Single x, y, w = width, h = height;
+ sizes.calcSizes (this, rr.width(), rr.height(), x, y, w, h);
+ if (width > 0 && height > 0 && w > 0 && h > 0)
+ switch (fit) {
+ case fit_meet: {
+ float iasp = 1.0 * width / height;
+ float rasp = 1.0 * w / h;
+ if (iasp > rasp)
+ h = height * w / width;
+ else
+ w = width * h / height;
+ break;
+ }
+ case fit_scroll:
+ case fit_hidden:
+ w = width;
+ h = height;
+ break;
+ case fit_slice: {
+ float iasp = 1.0 * width / height;
+ float rasp = 1.0 * w / h;
+ if (iasp > rasp)
+ w = width * h / height;
+ else
+ h = height * w / width;
+ break;
+ }
+ default: {} // fit_fill
+ }
+ return SRect (x, y, w, h);
+ }
+ return SRect ();
+}
+
+bool SMIL::MediaType::handleEvent (EventPtr event) {
+ Surface *s = surface();
+ switch (event->id ()) {
+ case event_postponed: {
+ PostponedEvent * pe = static_cast <PostponedEvent *> (event.ptr ());
+ static_cast<MediaTypeRuntime*>(runtime())->postpone (pe->is_postponed);
+ return true;
+ }
+ case event_timer: {
+ TimerEvent * te = static_cast <TimerEvent *> (event.ptr ());
+ if (te && te->timer_info) {
+ if (te->timer_info->event_id == trans_timer_id) {
+ if (trans_step >= trans_steps)
+ active_trans = NULL;
+ else
+ te->interval = trans_step++ < trans_steps;
+ if (s && s->parentNode())
+ s->parentNode()->repaint (s->bounds);
+ return true;
+ } else if (te->timer_info->event_id == trans_out_timer_id) {
+ active_trans = trans_out;
+ Transition * trans = convertNode <Transition> (trans_out);
+ if (trans) {
+ if (trans_timer) // eg. overlapping transIn/transOut
+ document ()->cancelTimer (trans_timer);
+ trans_step = 1;
+ if (Transition::Fade == trans->type) {
+ trans_steps = trans->dur;
+ trans_timer = document()->setTimeout(this, 100, trans_timer_id);
+ } else {
+ trans_steps = 4 * trans->dur;
+ trans_timer = document()->setTimeout(this, 25, trans_timer_id);
+ }
+ trans_out_active = true;
+ if (s)
+ s->repaint ();
+ }
+ return true;
+ }
+ }
+ } // fall through
+ default:
+ return TimedMrl::handleEvent (event);
+ }
+}
+
+KDE_NO_EXPORT NodeRefListPtr SMIL::MediaType::listeners (unsigned int id) {
+ NodeRefListPtr l = mouse_listeners.listeners (id);
+ if (l)
+ return l;
+ switch (id) {
+ case mediatype_attached:
+ return m_MediaAttached;
+ }
+ return TimedMrl::listeners (id);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT
+SMIL::AVMediaType::AVMediaType (NodePtr & d, const QString & t)
+ : SMIL::MediaType (d, t, id_node_audio_video) {}
+
+KDE_NO_EXPORT NodePtr SMIL::AVMediaType::childFromTag (const QString & tag) {
+ return fromXMLDocumentTag (m_doc, tag);
+}
+
+KDE_NO_EXPORT void SMIL::AVMediaType::defer () {
+ setState (state_deferred);
+ MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ());
+ if (mr->state () == Runtime::timings_started)
+ mr->postpone_lock = document ()->postpone ();
+}
+
+KDE_NO_EXPORT void SMIL::AVMediaType::undefer () {
+ setState (state_activated);
+ MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ());
+ if (mr->state () == Runtime::timings_started) {
+ mr->postpone_lock = 0L;
+ mr->started ();
+ }
+}
+
+KDE_NO_EXPORT void SMIL::AVMediaType::endOfFile () {
+ if (!active())
+ return; // backend eof after a reset
+ MediaTypeRuntime * mr = static_cast <MediaTypeRuntime *> (runtime ());
+ mr->postpone_lock = 0L;
+ mr->propagateStop (true);
+}
+
+KDE_NO_EXPORT Runtime * SMIL::AVMediaType::getNewRuntime () {
+ return new AudioVideoData (this);
+}
+
+KDE_NO_EXPORT void SMIL::AVMediaType::accept (Visitor * v) {
+ v->visit (this);
+}
+
+KDE_NO_EXPORT bool SMIL::AVMediaType::expose () const {
+ return !src.isEmpty () && !external_tree;
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT
+SMIL::ImageMediaType::ImageMediaType (NodePtr & d)
+ : SMIL::MediaType (d, "img", id_node_img) {}
+
+KDE_NO_EXPORT Runtime * SMIL::ImageMediaType::getNewRuntime () {
+ return new ImageRuntime (this);
+}
+
+KDE_NO_EXPORT NodePtr SMIL::ImageMediaType::childFromTag (const QString & tag) {
+ if (!strcmp (tag.latin1 (), "imfl"))
+ return new RP::Imfl (m_doc);
+ return SMIL::MediaType::childFromTag (tag);
+}
+
+KDE_NO_EXPORT void SMIL::ImageMediaType::accept (Visitor * v) {
+ v->visit (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT
+SMIL::TextMediaType::TextMediaType (NodePtr & d)
+ : SMIL::MediaType (d, "text", id_node_text) {}
+
+KDE_NO_EXPORT Runtime * SMIL::TextMediaType::getNewRuntime () {
+ return new TextRuntime (this);
+}
+
+KDE_NO_EXPORT void SMIL::TextMediaType::accept (Visitor * v) {
+ v->visit (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT
+SMIL::RefMediaType::RefMediaType (NodePtr & d)
+ : SMIL::MediaType (d, "ref", id_node_ref) {}
+
+KDE_NO_EXPORT Runtime * SMIL::RefMediaType::getNewRuntime () {
+ return new AudioVideoData (this); // FIXME check mimetype first
+}
+
+KDE_NO_EXPORT void SMIL::RefMediaType::accept (Visitor * v) {
+ v->visit (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT SMIL::Brush::Brush (NodePtr & d)
+ : SMIL::MediaType (d, "brush", id_node_brush) {}
+
+KDE_NO_EXPORT void SMIL::Brush::accept (Visitor * v) {
+ v->visit (this);
+}
+
+KDE_NO_EXPORT Runtime * SMIL::Brush::getNewRuntime () {
+ return new MediaTypeRuntime (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT Runtime * SMIL::Set::getNewRuntime () {
+ return new SetData (this);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT Runtime * SMIL::Animate::getNewRuntime () {
+ return new AnimateData (this);
+}
+
+KDE_NO_EXPORT bool SMIL::Animate::handleEvent (EventPtr event) {
+ if (event->id () == event_timer) {
+ TimerEvent * te = static_cast <TimerEvent *> (event.ptr ());
+ if (te && te->timer_info && te->timer_info->event_id == anim_timer_id) {
+ if (static_cast <AnimateData *> (runtime ())->timerTick () &&
+ te->timer_info)
+ te->interval = true;
+ return true;
+ }
+ }
+ return TimedMrl::handleEvent (event);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT Runtime *SMIL::AnimateMotion::getNewRuntime () {
+ return new AnimateMotionData (this);
+}
+
+KDE_NO_EXPORT bool SMIL::AnimateMotion::handleEvent (EventPtr event) {
+ if (event->id () == event_timer) {
+ TimerEvent * te = static_cast <TimerEvent *> (event.ptr ());
+ if (te && te->timer_info && te->timer_info->event_id == anim_timer_id) {
+ if (static_cast <AnimateMotionData *> (runtime ())->timerTick () &&
+ te->timer_info)
+ te->interval = true;
+ return true;
+ }
+ }
+ return TimedMrl::handleEvent (event);
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void SMIL::Param::activate () {
+ setState (state_activated);
+ QString name = getAttribute (StringPool::attr_name);
+ Node * parent = parentNode ().ptr ();
+ if (!name.isEmpty () && parent && parent->isElementNode ())
+ static_cast<Element*>(parent)->setParam (name,
+ getAttribute (StringPool::attr_value));
+ Element::activate (); //finish (); // no livetime of itself, will deactivate
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Region * n) {
+ visit (static_cast <SMIL::RegionBase *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Layout * n) {
+ visit (static_cast <SMIL::RegionBase *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Transition * n) {
+ visit (static_cast <Element *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::TimedMrl * n) {
+ visit (static_cast <Element *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::MediaType * n) {
+ visit (static_cast <SMIL::TimedMrl *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::ImageMediaType * n) {
+ visit (static_cast <SMIL::MediaType *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::TextMediaType * n) {
+ visit (static_cast <SMIL::MediaType *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::RefMediaType * n) {
+ visit (static_cast <SMIL::MediaType *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::AVMediaType * n) {
+ visit (static_cast <SMIL::MediaType *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Brush * n) {
+ visit (static_cast <SMIL::MediaType *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Anchor * n) {
+ visit (static_cast <SMIL::LinkingBase *> (n));
+}
+
+KDE_NO_EXPORT void Visitor::visit (SMIL::Area * n) {
+ visit (static_cast <SMIL::LinkingBase *> (n));
+}
+
+//-----------------------------------------------------------------------------
+
+KDE_NO_CDTOR_EXPORT ImageRuntime::ImageRuntime (NodePtr e)
+ : MediaTypeRuntime (e), img_movie (0L)
+{}
+
+KDE_NO_CDTOR_EXPORT ImageRuntime::~ImageRuntime () {
+ delete img_movie;
+}
+
+KDE_NO_EXPORT
+bool ImageRuntime::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "ImageRuntime::param " << name << "=" << val << endl;
+ if (name == StringPool::attr_src) {
+ killWGet ();
+ NodePtr element_protect = element;
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (!mt)
+ return false; // can not happen
+ if (mt->external_tree)
+ mt->removeChild (mt->external_tree);
+ mt->src = val;
+ if (!val.isEmpty ()) {
+ QString abs = mt->absolutePath ();
+ cached_img.setUrl (abs);
+ if (cached_img.isEmpty ()) {
+ wget (abs);
+ } else {
+ mt->width = cached_img.data->image->width ();
+ mt->height = cached_img.data->image->height ();
+ }
+ }
+ } else
+ return MediaTypeRuntime::parseParam (name, val);
+ return true;
+}
+
+/**
+ * start_timer timer expired, repaint if we have an image
+ */
+KDE_NO_EXPORT void ImageRuntime::started () {
+ if (element && downloading ()) {
+ postpone_lock = element->document ()->postpone ();
+ return;
+ }
+ MediaTypeRuntime::started ();
+}
+
+KDE_NO_EXPORT void ImageRuntime::clipStart () {
+ if (img_movie) {
+ img_movie->restart ();
+ if (img_movie->paused ())
+ img_movie->unpause ();
+ }
+ MediaTypeRuntime::clipStart ();
+}
+
+KDE_NO_EXPORT void ImageRuntime::clipStop () {
+ if (img_movie && frame_nr)
+ img_movie->pause ();
+ MediaTypeRuntime::clipStop ();
+}
+
+KDE_NO_EXPORT void ImageRuntime::remoteReady (QByteArray & data) {
+ NodePtr element_protect = element; // note element is weak
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (data.size () && mt) {
+ mt->resetSurface ();
+ QString mime = mimetype ();
+ kdDebug () << "ImageRuntime::remoteReady " << mime << " empty:" << cached_img.isEmpty () << " " << mt->src << endl;
+ if (mime.startsWith (QString::fromLatin1 ("text/"))) {
+ QTextStream ts (data, IO_ReadOnly);
+ readXML (element, ts, QString ());
+ Mrl *mrl = mt->external_tree ? mt->external_tree->mrl () : NULL;
+ if (mrl) {
+ mt->width = mrl->width;
+ mt->height = mrl->height;
+ }
+ }
+ if (!mt->external_tree && cached_img.isEmpty ()) {
+ delete img_movie;
+ img_movie = 0L;
+ QImage *pix = new QImage (data);
+ if (!pix->isNull ()) {
+ cached_img.data->image = pix;
+ img_movie = new QMovie (data, data.size ());
+ img_movie->connectUpdate(this,SLOT(movieUpdated(const QRect&)));
+ img_movie->connectStatus (this, SLOT (movieStatus (int)));
+ img_movie->connectResize(this,SLOT (movieResize(const QSize&)));
+ frame_nr = 0;
+ mt->width = pix->width ();
+ mt->height = pix->height ();
+ if (mt->surface ())
+ mt->sub_surface->repaint ();
+ } else
+ delete pix;
+ }
+ }
+ postpone_lock = 0L;
+ if (timingstate == timings_started)
+ started ();
+}
+
+KDE_NO_EXPORT void ImageRuntime::movieUpdated (const QRect &) {
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (mt && frame_nr++) {
+ mt->resetSurface ();
+ cached_img.setUrl (QString ());
+ ASSERT (cached_img.data && cached_img.isEmpty ());
+ cached_img.data->image = new QImage;
+ *cached_img.data->image = (img_movie->framePixmap ());
+ if (mt->surface())
+ mt->sub_surface->repaint ();
+ }
+ if (timingstate != timings_started && img_movie)
+ img_movie->pause ();
+}
+
+KDE_NO_EXPORT void ImageRuntime::movieStatus (int s) {
+ if (element && element->state >= Node::state_began &&
+ SMIL::TimedMrl::keepContent (element)) {
+ if (s == QMovie::EndOfMovie) {
+ propagateStop (false);
+ }
+ }
+}
+
+KDE_NO_EXPORT void ImageRuntime::movieResize (const QSize &) {
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (mt->surface ())
+ mt->sub_surface->repaint ();
+ //kdDebug () << "movieResize" << endl;
+}
+
+KDE_NO_EXPORT void ImageRuntime::postpone (bool b) {
+ kdDebug () << "ImageRuntime::postpone " << b << endl;
+ if (img_movie) {
+ if (!img_movie->paused () && b)
+ img_movie->pause ();
+ else if (img_movie->paused () && !b)
+ img_movie->unpause ();
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+namespace KMPlayer {
+ class TextRuntimePrivate {
+ public:
+ TextRuntimePrivate () {
+ reset ();
+ }
+ void reset () {
+ codec = 0L;
+ font = QApplication::font ();
+ data.truncate (0);
+ }
+ QByteArray data;
+ QTextCodec * codec;
+ QFont font;
+ };
+}
+
+KDE_NO_CDTOR_EXPORT TextRuntime::TextRuntime (NodePtr e)
+ : MediaTypeRuntime (e), d (new TextRuntimePrivate) {
+ reset ();
+}
+
+KDE_NO_CDTOR_EXPORT TextRuntime::~TextRuntime () {
+ delete d;
+}
+
+KDE_NO_EXPORT void TextRuntime::reset () {
+ d->reset ();
+ font_size = d->font.pointSize ();
+ font_color = 0;
+ background_color = 0xffffff;
+ bg_opacity = 100;
+ halign = align_left;
+ MediaTypeRuntime::reset ();
+}
+
+KDE_NO_EXPORT
+bool TextRuntime::parseParam (const TrieString & name, const QString & val) {
+ //kdDebug () << "TextRuntime::parseParam " << name << "=" << val << endl;
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (!mt)
+ return false; // cannot happen
+ if (name == StringPool::attr_src) {
+ killWGet ();
+ mt->src = val;
+ d->data.resize (0);
+ if (!val.isEmpty ())
+ wget (mt->absolutePath ());
+ return true;
+ }
+ if (name == "backgroundColor" || name == "background-color") {
+ background_color = val.isEmpty () ? 0xffffff : QColor (val).rgb ();
+ } else if (name == "fontColor") {
+ font_color = val.isEmpty () ? 0 : QColor (val).rgb ();
+ } else if (name == "charset") {
+ d->codec = QTextCodec::codecForName (val.ascii ());
+ } else if (name == "fontFace") {
+ ; //FIXME
+ } else if (name == "fontPtSize") {
+ font_size = val.isEmpty () ? d->font.pointSize () : val.toInt ();
+ } else if (name == "fontSize") {
+ font_size += val.isEmpty () ? d->font.pointSize () : val.toInt ();
+ } else if (name == "backgroundOpacity") {
+ bg_opacity = (int) SizeType (val).size (100);
+ } else if (name == "hAlign") {
+ const char * cval = val.ascii ();
+ if (!cval)
+ halign = align_left;
+ else if (!strcmp (cval, "center"))
+ halign = align_center;
+ else if (!strcmp (cval, "right"))
+ halign = align_right;
+ else
+ halign = align_left;
+ // TODO: expandTabs fontBackgroundColor fontSize fontStyle fontWeight hAlig vAlign wordWrap
+ } else
+ return MediaTypeRuntime::parseParam (name, val);
+ mt->resetSurface ();
+ if (mt->surface ())
+ mt->sub_surface->repaint ();
+ return true;
+}
+
+/**
+ * start_timer timer expired, repaint if we have text
+ */
+KDE_NO_EXPORT void TextRuntime::started () {
+ if (element && downloading ()) {
+ postpone_lock = element->document ()->postpone ();
+ return;
+ }
+ MediaTypeRuntime::started ();
+}
+
+KDE_NO_EXPORT void TextRuntime::remoteReady (QByteArray & data) {
+ QString str (data);
+ SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
+ if (mt && data.size ()) {
+ d->data = data;
+ mt->resetSurface ();
+ if (d->data.size () > 0 && !d->data [d->data.size () - 1])
+ d->data.resize (d->data.size () - 1); // strip zero terminate char
+ QTextStream ts (d->data, IO_ReadOnly);
+ if (d->codec)
+ ts.setCodec (d->codec);
+ text = ts.read ();
+ if (mt->surface ())
+ mt->sub_surface->repaint ();
+ }
+ postpone_lock = 0L;
+ if (timingstate == timings_started)
+ started ();
+}
+
+//-----------------------------------------------------------------------------
+
+#include "kmplayer_smil.moc"