📄 time_node.cpp
字号:
// This file is part of Ambulant Player, www.ambulantplayer.org.//// Copyright (C) 2003-2007 Stichting CWI, // Kruislaan 413, 1098 SJ Amsterdam, The Netherlands.//// Ambulant Player is free software; you can redistribute it and/or modify// it under the terms of the GNU Lesser General Public License as published by// the Free Software Foundation; either version 2.1 of the License, or// (at your option) any later version.//// Ambulant Player 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 Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public License// along with Ambulant Player; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA/* * @$Id: time_node.cpp,v 1.76 2007/02/12 14:15:22 jackjansen Exp $ */#include "ambulant/smil2/time_node.h"#include "ambulant/smil2/animate_n.h"#include "ambulant/smil2/animate_e.h"#include "ambulant/smil2/time_calc.h"#include <cmath>#include <stack>#include <set>#include <list>#include "ambulant/lib/logger.h"//#define AM_DBG if(1)#ifndef AM_DBG#define AM_DBG if(0)#endif#ifndef AMBULANT_NO_IOSTREAMS#include <iostream>#endifusing namespace ambulant;using namespace smil2;// static (mem verifier)int time_node::node_counter = 0;time_node::time_node(context_type *ctx, const node *n, time_container_type type /* = tc_none */, bool discrete /* = false */) : m_context(ctx), m_node(n), m_attrs(n), m_type(type), m_discrete(discrete), m_timer(0), m_state(0), m_interval(interval_type::unresolved), m_active(false), m_needs_remove(false), m_rad(0), m_precounter(0), m_priority(0), m_paused(false), m_pad(0), m_paused_sync_time(0), m_deferred(false), m_ffwd_mode(false), m_update_event(false, qtime_type(0, 0)), m_transout_sr(0), m_begin_event_inst(time_type::unresolved), m_domcall_rule(0), m_locked(false), m_want_activate_events(false), m_want_focusin_events(false), m_want_focusout_events(false), m_want_inbounds_events(false), m_want_outofbounds_events(false), m_want_accesskey(false), m_impldur(time_type::unresolved), m_last_cdur(time_type::unresolved), m_logger(0), m_parent(0), m_next(0), m_child(0) { assert(type <= tc_none); node_counter++; m_logger = lib::logger::get_logger(); m_time_calc = new time_calc(this); create_time_states(); m_state = m_time_states[ts_reset];} time_node::~time_node() { node_counter--; // Delete the timer of this node delete m_timer; // Delete begin and end list rules rule_list::iterator it; for(it=m_begin_list.begin();it!=m_begin_list.end();it++) delete (*it); for(it=m_end_list.begin();it!=m_end_list.end();it++) delete (*it); delete m_transout_sr; // This node owns the lists but not // the sync_rules within the lists. dependency_map::iterator dit; for(dit=m_dependents.begin();dit!=m_dependents.end();dit++) delete (*dit).second; // delete this time states for(int i=0;i<=ts_dead;i++) delete m_time_states[i]; delete m_time_calc; // Delete recursively this branch node_navigator<time_node>::delete_tree(this); }// A time node can be at any moment in one of the following 5 states:// reset, proactive, active, postactive, dead// So, a node is a FSM.// For the current implementation the engine is// represented by this node whereas the states// by an instance of the time_state class.void time_node::create_time_states() { m_time_states[ts_reset] = new reset_state(this); m_time_states[ts_proactive] = new proactive_state(this); m_time_states[ts_active] = new active_state(this); m_time_states[ts_postactive] = new postactive_state(this); m_time_states[ts_dead] = new dead_state(this);}// Helper function that collects time instances from the provided rules. void time_node::get_instance_times(const rule_list& rules, time_mset& set) const { rule_list::const_iterator it; for(it=rules.begin();it!=rules.end();it++) (*it)->get_instance_times(set);}// Helper function that resets time instances of the provided rules. // Resets instance times following the spec rules for a reset.void time_node::reset(rule_list& rules, time_node *src) { rule_list::iterator it; for(it=rules.begin();it!=rules.end();it++) (*it)->reset(src);}// DOM TimeElement::startElement()// Starts a node at t = 0.// Currently supported only for the root.void time_node::start() { if(!m_domcall_rule) { m_domcall_rule = new event_rule(this, tn_dom_call); add_begin_rule(m_domcall_rule); } qtime_type timestamp(this, 0); // Bring node to live if(!is_alive()) set_state(ts_proactive, timestamp, this); // Add event instance m_domcall_rule->add_instance(timestamp, 0);}// DOM TimeElement::stopElement()// Currently supported only for the root.void time_node::stop() { qtime_type timestamp(this, get_simple_time()); //set_state(ts_postactive, timestamp, this); reset(timestamp, this);}// DOM TimeElement::pauseElement()void time_node::pause() { // Pause the local time line // Pause children // Pause playable if a media node}// DOM TimeElement::resumeElement()void time_node::resume() { // Resume the local time line // Resume children // Resume playable if a media node}// Adds a sync_rule to the begin list of this node.// This node is not the sync base but the target (e.g. the node that will be affected).// This is similar to how begin and end conditions are specified in the smil doc.// This node is the owner of the sync_rule but not the source of the event. void time_node::add_begin_rule(sync_rule *sr) { sr->set_target(this, rt_begin); time_node* tn = sr->get_syncbase(); sync_event se = sr->get_syncbase_event(); assert(tn!=0); tn->add_dependent(sr, se); m_begin_list.push_back(sr);}// Adds a sync_rule to the end list of this node.// This node is not the sync base but the target.void time_node::add_end_rule(sync_rule *sr) { sr->set_target(this, rt_end); time_node* tn = sr->get_syncbase(); sync_event se = sr->get_syncbase_event(); assert(tn!=0); tn->add_dependent(sr, se); m_end_list.push_back(sr);}// Sets a sync_rule for the out transition of this node.// This node is not the sync base but the target.void time_node::set_transout_rule(sync_rule *sr) { sr->set_target(this, rt_transout); time_node* tn = sr->get_syncbase(); sync_event se = sr->get_syncbase_event(); assert(tn!=0); tn->add_dependent(sr, se); m_transout_sr = sr;}// Adds a sync arc from this node to a targetvoid time_node::add_dependent(sync_rule *sr, sync_event ev) { dependency_map::iterator it = m_dependents.find(ev); rule_list *p = 0; if(it == m_dependents.end() || (*it).second == 0) { p = new rule_list(); m_dependents[ev] = p; } else { p = (*it).second; } sr->set_syncbase(this, ev); p->push_back(sr);}// Retuns the local name of this nodestd::string time_node::to_string() const { if(get_type() == tc_none) return dom_node()->get_local_name(); return get_type_as_str();}std::string time_node::get_sig() const { std::string rv = "time_node(" + to_string() + ", "; const lib::node *domnode = dom_node(); if (domnode) rv += domnode->get_sig(); else rv += "NULL"; rv += ")"; return rv;}// Returns the implicit duration of this node. // This is an implementation for a leaf-node.// e.g. it queries playable for the implicit dur.// The last definite implicit duration returned by the // playable is stored in the variable m_impldur.// This function is called if and only if the implicit// duration of a node is required by the timing model.// See time_container::get_implicit_dur()// See seq::get_implicit_dur()time_node::time_type time_node::get_implicit_dur() { // This function is not applicable for containers. // Assert this usage. assert(!is_time_container()); // If this is a discrete leaf node, we know the answer if(is_discrete()) { AM_DBG m_logger->debug("get_implicit_dur(%s[%s]) return 0 for discrete", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); return time_type(0); } // Was the implicit duration calculated before? // If yes, avoid the overhead of querring if(m_impldur != time_type::unresolved) { AM_DBG m_logger->debug("get_implicit_dur(%s[%s]) return cached %s", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(m_impldur).c_str()); return m_impldur; } // Can the associated playable provide the implicit duration? m_impldur = get_playable_dur(); if(m_ffwd_mode && m_impldur == time_type::unresolved) { AM_DBG m_logger->debug("get_implicit_dur(%s[%s]) return 1000 for ffwd_mode", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); return 1000; } // Trace the return value of this function AM_DBG m_logger->debug("%s[%s].get_implicit_dur(): %s", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(m_impldur).c_str()); return m_impldur;}voidtime_node::set_ffwd_mode(bool b){ AM_DBG m_logger->debug("set_ffwd_mode(%d) for %s", (int)b, get_sig().c_str()); m_ffwd_mode = b; if (m_ffwd_mode && is_playable()) { AM_DBG m_logger->debug("set_ffwd_mode: stop_playable(%s)", get_sig().c_str()); stop_playable(); }#if 0 std::list<time_node*> children; get_children(children); std::list<time_node*>::iterator it; for(it = children.begin(); it != children.end(); it++) { (*it)->set_ffwd_mode(b); }#endif}// This function calculates the simple duration of this node.// See spec: "Defining the simple duration" // The last calculated simple duration is stored in the variable m_last_cdur.// This function will call the function "get_implicit_dur()" if and only if // the implicit duration of a node is required by the timing model.// Delegates the actual work to the associated time_calc instance.time_node::time_type time_node::calc_dur() { m_last_cdur = m_time_calc->calc_dur(); return m_last_cdur;}// Returns true when the implicit duration is // required by the model for timing calculationsbool time_node::needs_implicit_dur() const { if(is_time_container() || is_discrete()) return false; if(!m_attrs.has_dur_specifier() && m_attrs.specified_end()) { return false; } dur_type dt = m_attrs.get_dur_type(); if(dt == dt_unspecified || dt == dt_media) return true; return false;}// Calculates and returns the current inteval end.// This uses calc_ad() function.// Delegates the actual work to the associated time_calc instance.time_node::time_type time_node::calc_current_interval_end() { time_mset end_list; get_instance_times(m_end_list, end_list); return m_time_calc->calc_interval_end(m_interval, end_list);}// Calculates the first valid interval for this node. // Delegates the actual work to the associated time_calc instance.// Calcs are done within the context of a parent simple dur// A valid interval has to overlap with parent's simple durationtime_node::interval_type time_node::calc_first_interval() { // Get the begin instance list time_mset begin_list; get_instance_times(m_begin_list, begin_list); if(m_begin_event_inst != time_type::unresolved) { begin_list.insert(m_begin_event_inst); m_begin_event_inst = time_type::unresolved; } // Get the end instance list time_mset end_list; get_instance_times(m_end_list, end_list); // Parent simple duration time_type parent_simple_dur = up()?up()->get_last_dur():time_type::indefinite; return m_time_calc->calc_first_interval(begin_list, end_list, parent_simple_dur);}// Calculates the next acceptable interval for this node.// Delegates the actual work to the associated time_calc instance.// Calcs are done within the context of a parent simple dur// An valid interval has to overlap with parent's simple duration// An interval should begin after the previous end// A zero-dur previous interval affects calcs time_node::interval_type time_node::calc_next_interval(interval_type prev) { if(prev == interval_type::unresolved) { if(m_history.empty()) { // xxx: add warn return interval_type::unresolved; } prev = m_history.back(); } // Get the begin instance list
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -