📄 timegraph.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: timegraph.cpp,v 1.24 2007/02/12 14:15:23 jackjansen Exp $ */#include "ambulant/lib/document.h"#include "ambulant/lib/node.h"#include "ambulant/lib/logger.h"#include "ambulant/common/schema.h"#include "ambulant/smil2/timegraph.h"#include "ambulant/smil2/time_node.h"#include "ambulant/smil2/animate_n.h"#include "ambulant/smil2/time_attrs.h"#include "ambulant/smil2/test_attrs.h"#include "ambulant/smil2/sync_rule.h"#include <cmath>#include <stack>#include <cstdlib>//#define AM_DBG if(1)#ifndef AM_DBG#define AM_DBG if(0)#endifusing namespace ambulant;using namespace smil2;timegraph::timegraph(time_node::context_type *ctx, const document *doc, const schema *sch) : m_context(ctx), m_schema(sch), m_root(0), m_dom2tn(0) { assert(doc!=0); assert(sch!=0); m_logger = lib::logger::get_logger(); m_dom2tn = new std::map<int, time_node*>(); m_root = build_time_tree(doc->get_root()); AM_DBG m_logger->debug("Time nodes created: %d", time_node::get_node_counter()); build_priorities(); build_time_graph(); build_timers_graph(); build_trans_out_graph();}timegraph::~timegraph() { if(m_root) { delete m_root; AM_DBG m_logger->debug("Undeleted time nodes: %d", time_node::get_node_counter()); } // else detached if(m_dom2tn) delete m_dom2tn;}time_node* timegraph::detach_root() { time_node* tmp = m_root; m_root = 0; return tmp;}std::map<int, time_node*>* timegraph::detach_dom2tn() { std::map<int, time_node*>* tmp = m_dom2tn; m_dom2tn = 0; return tmp;}time_node* timegraph::build_time_tree(const lib::node *root) { const std::set<std::string>& te = m_schema->get_time_elements(); time_node *time_root = 0; std::stack<time_node*> stack; std::stack<const lib::node*> switch_stack; std::stack<const lib::node*> select_stack; lib::node::const_iterator it; lib::node::const_iterator end = root->end(); int localIdCounter = 1; for(it = root->begin(); it != end; it++) { std::pair<bool, const lib::node*> pair = *it; bool start_element = pair.first; const lib::node *n = pair.second; const std::string& tag = n->get_local_name(); // keep switch tree ref if(tag == "switch") { if(start_element) { switch_stack.push(n); select_stack.push(select_switch_child(n)); } else { switch_stack.pop(); select_stack.pop(); } } // <a actuate="onLoad"/> we treat as area. This is not pretty, but it // works. bool is_onload_a = false; if (tag == "a" && n->down() == NULL) { const char *actuate = n->get_attribute("actuate"); if (actuate && strcmp(actuate, "onLoad") == 0) is_onload_a = true; } // if not a time element then continue to next if(te.find(tag) == te.end() && !is_onload_a) continue; // when within a switch and not selected then continue to next if(!switch_stack.empty() && (select_stack.top() == 0 || !const_nnhelper::is_descendent(n, select_stack.top()))) { // skip node content it++; while((*it).second != n) it++; continue; } // support inline tests test_attrs ta(n); if(!ta.selected()) { // skip content AM_DBG m_logger->debug("Filtering out node: %s[%s]", ta.get_tag().c_str(), ta.get_id().c_str()); it++; while((*it).second != n) it++; continue; } if(start_element) { // create a time node for each start element time_node *tn = create_time_node(n, stack.empty()?0:stack.top()); // add 'a' parent as a child if(n->up() && n->up()->get_local_name() == "a") { time_node *tnp = create_time_node(n->up(), tn); tn->append_child(tnp); const char *pidp = n->get_attribute("id"); if(pidp) m_id2tn[pidp] = tn; } // read or create node id and add it the map std::string ident; const char *pid = n->get_attribute("id"); if(pid) ident = pid; else { ident += "aid"; char b[32];sprintf(b,"%u",localIdCounter++); ident += b; } m_id2tn[ident] = tn; if(stack.empty()) { assert(time_root == 0); time_root = tn; } else { // container or media with area or animate elements, etc stack.top()->append_child(tn); } stack.push(tn); } else { stack.pop(); } } return time_root;}time_node* timegraph::create_time_node(const node* n, time_node* tparent) const { time_node *tn = 0; time_container_type tct = m_schema->get_time_type(n->get_qname()); if(tct == tc_seq) tn = new seq(m_context, n); else if(tct == tc_par) tn = new par(m_context, n); else if(tct == tc_excl) tn = new excl(m_context, n); else if(m_schema->is_animation(n->get_qname())) tn = animate_node::new_instance(m_context, n, tparent->dom_node()); else tn = new time_node(m_context, n, tc_none, m_schema->is_discrete(n->get_qname())); (*m_dom2tn)[n->get_numid()] = tn; return tn;}void timegraph::build_time_graph() { time_node::iterator it; time_node::iterator end = m_root->end(); for(it = m_root->begin(); it != end; it++) { if(!(*it).first) continue; time_node *tn = (*it).second; add_begin_sync_rules(tn); add_end_sync_rules(tn); if(tn->is_link() && tn->get_time_attrs()->get_actuate() == actuate_onrequest) { tn->set_want_activate_event(true); } }}void timegraph::build_priorities() { time_node::iterator it; time_node::iterator end = m_root->end(); for(it = m_root->begin(); it != end; it++) { if(!(*it).first) continue; time_node *tn = (*it).second; if(tn->is_excl()) { excl *e = qualify<excl*>(tn); e->built_priorities(); } }}// Builds the network of timers based on the sync behavior declared in the document// The spec allows many aspects to be implementation specific // XXX: for now assume always "can slip sync behavior".void timegraph::build_timers_graph() { if(!m_context->get_timer()) return; // not supported by context time_node::iterator it; time_node::iterator end = m_root->end(); for(it = m_root->begin(); it != end; it++) { if(!(*it).first) continue; time_node *tn = (*it).second; lib::timer_control *timer = 0; if(tn->is_root()) timer = new lib::timer_control_impl(m_context->get_timer(), 1.0, false); else timer = new lib::timer_control_impl(tn->up()->get_timer(), 1.0, false); tn->set_timer(timer); }}// Adds sync rules for out transitionsvoid timegraph::build_trans_out_graph() { time_node::iterator it; time_node::iterator end = m_root->end(); for(it = m_root->begin(); it != end; it++) { if(!(*it).first) continue; time_node *tn = (*it).second; const time_attrs *ta = tn->get_time_attrs(); if(!ta->get_trans_out()) continue; time_type offset = -ta->get_trans_out_dur(); // We should now arrange so that the out transition // starts before the node is removed.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -