You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kmplayer/src/kmplayer_smil.cpp

3605 lines
121 KiB

/**
* Copyright (C) 2005-2007 by Koos Vriezen <koos.vriezen@gmail.com>
*
* 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 <tqtextstream.h>
#include <tqcolor.h>
#include <tqpixmap.h>
#include <tqmovie.h>
#include <tqimage.h>
#include <tqtextcodec.h>
#include <tqfont.h>
#include <tqapplication.h>
#include <tqregexp.h>
#include <tqtimer.h>
#include <kdebug.h>
#include <kurl.h>
#include <kmimetype.h>
#include <tdeio/job.h>
#include <tdeio/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 TQString & vl, int & dur) {
const char * cval = vl.ascii ();
if (!cval) {
dur = 0;
return false;
}
int sign = 1;
bool fp_seen = false;
TQString 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 += TQChar (*p);
} else if (*p == '.') {
if (fp_seen)
break;
else
num += TQChar (*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 TQString & 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);
TQString 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 TQString & 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 TQString & 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 TQString & val) {
int dur = -2; // also 0 for 'media' duration, so it will not update then
TQString vs = val.stripWhiteSpace ();
TQString vl = vs.lower ();
const char * cval = vl.ascii ();
int offset = 0;
//kdDebug () << "setDuration1 " << vl << endl;
if (cval && cval[0]) {
TQString 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 += TQChar ('\\');
last_esc = false;
} else
last_esc = true;
} else if (*q == '.' && !last_esc) {
break;
} else
idref += TQChar (*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 TQString & 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 TQString & s) {
*this = s;
}
void SizeType::reset () {
perc_size = 0;
abs_size = 0;
isset = false;
}
SizeType & SizeType::operator = (const TQString & s) {
TQString strval (s);
int p = strval.find (TQChar ('%'));
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 = TQString::fromLatin1 ("topLeft");
}
static bool regPoints (const TQString & str, Single & x, Single & y) {
TQString 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);
TQString 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 TQString &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 TQString &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 TQString & 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 = TQStringList::split (TQString (";"), val);
} else if (name == "calcMode") {
if (val == TQString::fromLatin1 ("discrete"))
calcMode = calc_discrete;
else if (val == TQString::fromLatin1 ("linear"))
calcMode = calc_linear;
else if (val == TQString::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) {
TQRegExp 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, TQString ("%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 TQString & 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 = TQStringList::split (TQString (";"), val);
} else if (name == "keyTimes") {
TQStringList kts = TQStringList::split (TQString (";"), 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 = TQStringList::split (TQString (";"), val);
} else if (name == "calcMode") {
if (val == TQString::fromLatin1 ("discrete"))
calcMode = calc_discrete;
else if (val == TQString::fromLatin1 ("linear"))
calcMode = calc_linear;
else if (val == TQString::fromLatin1 ("paced"))
calcMode = calc_paced;
else if (val == TQString::fromLatin1 ("spline"))
calcMode = calc_spline;
} else
return AnimateGroupData::parseParam (name, val);
return true;
}
bool AnimateMotionData::getCoordinates (const TQString &coord, SizeType &x, SizeType &y) {
int p = coord.find (TQChar (','));
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) {
TQStringList kss = TQStringList::split (
TQString (" "), 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 TDEIO::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 TQString &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 TQString & 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 TQString & 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 TQString & 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 TQString & 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 TQString & tag) {
if (!strcmp (tag.latin1 (), "switch"))
return new SMIL::Switch (d);
return 0L;
}
//-----------------------------------------------------------------------------
KDE_NO_EXPORT NodePtr SMIL::Smil::childFromTag (const TQString & 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) {
TQString str = e->innerText ();
pretty_name = str.left (str.find (TQChar ('\n')));
} else if (e->id == id_node_meta) {
Element * elm = convertNode <Element> (e);
const TQString name = elm->getAttribute (StringPool::attr_name);
if (name == TQString::fromLatin1 ("title"))
pretty_name = elm->getAttribute ("content");
else if (name == TQString::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 TQString & 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 TQString & 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 TQString & 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, TQString::number(w_root));
rl->setAttribute(StringPool::attr_height,TQString::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, TQString::number ((int)w));
rl->setAttribute (StringPool::attr_height, TQString::number ((int)h));
rl->setParam (StringPool::attr_width, TQString::number((int)w));
rl->setParam (StringPool::attr_height,TQString::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 (TQString ());
postpone_lock = NULL;
killWGet ();
sizes.resetSizes ();
Element::deactivate ();
}
KDE_NO_EXPORT void SMIL::RegionBase::remoteReady (TQByteArray & data) {
TQImage *pix = new TQImage (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 TQString & 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 | TQColor (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;
TQString 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 TQString & 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 TQString & 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 TQString & 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 = TQColor (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) {
unsigned 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 TQString &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 TQString & 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);
TQString lang = elm->getAttribute ("systemLanguage");
if (!lang.isEmpty ()) {
lang = lang.replace (TQChar ('-'), TQChar ('_'));
char *clang = getenv ("LANG");
if (!clang) {
if (!fallback)
fallback = e;
} else if (TQString (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 TQString &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 TQString & tag) {
return fromMediaContentGroup (m_doc, tag);
}
//-----------------------------------------------------------------------------
KDE_NO_CDTOR_EXPORT SMIL::Area::Area (NodePtr & d, const TQString & 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 TQString & val) {
if (para == "coords") {
delete [] coords;
TQStringList clist = TQStringList::split (TQString (","), 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 TQString &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 TQString & 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 TQString & 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 TQString & t)
: SMIL::MediaType (d, t, id_node_audio_video) {}
KDE_NO_EXPORT NodePtr SMIL::AVMediaType::childFromTag (const TQString & 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 TQString & 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);
TQString 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 TQString & 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 ()) {
TQString 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 (TQByteArray & data) {
NodePtr element_protect = element; // note element is weak
SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
if (data.size () && mt) {
mt->resetSurface ();
TQString mime = mimetype ();
kdDebug () << "ImageRuntime::remoteReady " << mime << " empty:" << cached_img.isEmpty () << " " << mt->src << endl;
if (mime.startsWith (TQString::fromLatin1 ("text/"))) {
TQTextStream ts (data, IO_ReadOnly);
readXML (element, ts, TQString ());
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;
TQImage *pix = new TQImage (data);
if (!pix->isNull ()) {
cached_img.data->image = pix;
img_movie = new TQMovie (data, data.size ());
img_movie->connectUpdate(this,TQ_SLOT(movieUpdated(const TQRect&)));
img_movie->connectStatus (this, TQ_SLOT (movieStatus (int)));
img_movie->connectResize(this,TQ_SLOT (movieResize(const TQSize&)));
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 TQRect &) {
SMIL::MediaType * mt = convertNode <SMIL::MediaType> (element);
if (mt && frame_nr++) {
mt->resetSurface ();
cached_img.setUrl (TQString ());
ASSERT (cached_img.data && cached_img.isEmpty ());
cached_img.data->image = new TQImage;
*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 == TQMovie::EndOfMovie) {
propagateStop (false);
}
}
}
KDE_NO_EXPORT void ImageRuntime::movieResize (const TQSize &) {
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 = TQApplication::font ();
data.truncate (0);
}
TQByteArray data;
TQTextCodec * codec;
TQFont 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 TQString & 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 : TQColor (val).rgb ();
} else if (name == "fontColor") {
font_color = val.isEmpty () ? 0 : TQColor (val).rgb ();
} else if (name == "charset") {
d->codec = TQTextCodec::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 (TQByteArray & data) {
TQString 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
TQTextStream 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"