📄 time_node.cpp
字号:
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 dur time_type parent_simple_dur = up()?up()->get_last_dur():time_type::indefinite; return m_time_calc->calc_next_interval(begin_list, end_list, parent_simple_dur, prev.end, prev.is_zero_dur());}// Sets the state of this node.// timestamp: "scheduled now" in parent simple time// This is the state change hook for this node.void time_node::set_state(time_state_type state, qtime_type timestamp, time_node *oproot) { if(m_state->ident() == state) return; m_state->exit(timestamp, oproot); m_state = m_time_states[state]; m_state->enter(timestamp);}// Calls set_state() after checking for exclvoid time_node::set_state_ex(time_state_type tst, qtime_type timestamp) { // this should be true assert(timestamp.first == sync_node()); if(sync_node()->is_excl()) { excl *p = static_cast<excl*>(sync_node()); if(tst == ts_active) { p->interrupt(this, timestamp); } else if(tst == ts_postactive) { set_state(tst, timestamp, this); p->on_child_normal_end(this, timestamp); } return; } set_state(tst, timestamp, this);}// Cancels the current interval notifyings dependents.void time_node::cancel_interval(qtime_type timestamp) { AM_DBG m_logger->debug("%s[%s].cancel_interval(): %s", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(m_interval).c_str()); assert(m_interval.is_valid()); // The interval should be updated before sync_update // to make available the new info to induced calcs interval_type i = m_interval; m_interval = interval_type::unresolved; on_cancel_instance(timestamp, tn_begin, i.begin); on_cancel_instance(timestamp, tn_end, i.end);}// Updates the current interval with the one provided notifyings dependents.void time_node::update_interval(qtime_type timestamp, const interval_type& new_interval) { AM_DBG m_logger->debug("%s[%s].update_interval(): %s -> %s", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(m_interval).c_str(), ::repr(new_interval).c_str()); assert(m_interval.is_valid()); assert(timestamp.first == sync_node()); // The interval should be updated before sync_update // to make available the new info to induced calcs interval_type old = m_interval; m_interval = new_interval; if(m_interval.begin != old.begin) { time_type dt = m_interval.begin - timestamp.second; qtime_type qt(sync_node(), m_interval.begin); on_update_instance(timestamp, tn_begin, m_interval.begin, old.begin); raise_update_event(timestamp); } if(m_interval.end != old.end) { time_type dt = m_interval.end - timestamp.second; if(dt.is_definite()) { // Sync node is probably interested for this event. sync_node()->raise_update_event(timestamp); } on_update_instance(timestamp, tn_end, m_interval.end, old.end); }}// Updates the current interval end with the value provided notifyings dependents.void time_node::update_interval_end(qtime_type timestamp, time_type new_end) { AM_DBG m_logger->debug("%s[%s].update_interval_end(): %s -> %s at PT:%ld, DT:%ld", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(m_interval.end).c_str(), ::repr(new_end).c_str(), timestamp.second(), timestamp.as_doc_time_value()); if(!m_interval.is_valid()) return; time_type old_end = m_interval.end; // The interval should be updated before sync_update // to make available the new info to induced calcs m_interval.end = new_end; on_update_instance(timestamp, tn_end, new_end, old_end); // Sync node is probably interested for this event. if(up()) up()->raise_update_event(timestamp);}// Sets a new interval as current, updates dependents and schedules activation.// After this call the state of the node // a) Remains the same (proactive or postactive) if the interval is after timestamp.// In this case the interval is scheduled.// b) Transitions to postactive if the interval is before timestamp// c) Transitions to active if the interval contains timestamp// See active_state::enter() for the activities executed// when the node is activated.// param timestamp: "now" in parent simple timevoid time_node::set_interval(qtime_type timestamp, const interval_type& i) { AM_DBG m_logger->debug("%s[%s].set_current_interval(): %s (DT=%ld)", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(i).c_str(), timestamp.as_doc_time_value()); // verify the assumptions made in the following code assert(timestamp.first == sync_node()); assert(m_state->ident() == ts_proactive || m_state->ident() == ts_postactive); assert(is_root() || up()->m_state->ident() == ts_active); if(!can_set_interval(timestamp, i)) { raise_update_event(timestamp); return; } // Set the interval as current. m_interval = i; // Update dependents, event if this interval will never play on_new_instance(timestamp, tn_begin, m_interval.begin); on_new_instance(timestamp, tn_end, m_interval.end); // Update parent to recalc end sync status if(sync_node()->is_par() || sync_node()->is_excl()) sync_node()->raise_update_event(timestamp); // Is this a cut-off interval? // this can happen when proactive if(m_interval.before(timestamp.second)) { assert(m_state->ident() == ts_proactive); // Add to history and invalidate played_interval(timestamp); // Jump to post active set_state(ts_postactive, timestamp, this); return; } if(m_interval.after(timestamp.second)) { // Schedule activation: // activate at m_interval.begin - timestamp return; } // Else, the interval should be activated now assert(m_interval.contains(timestamp.second)); if(deferred()) defer_interval(timestamp); else set_state_ex(ts_active, timestamp);}// Returns true when the node can establish its interval// Fixes biased intervals// The design should be improved so that this function always returns true. bool time_node::can_set_interval(qtime_type timestamp, const interval_type& i) { if(is_root() || i.after(timestamp.second)) return true; if(up() && up()->is_seq()) { // the node should go active but the interval may be wrong/biased time_node *prev = previous(); if(prev && prev->is_active()) { // wait AM_DBG m_logger->debug("%s[%s] attempt to set_current_interval() but prev active: %s (DT=%ld)", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), ::repr(i).c_str(), timestamp.as_doc_time_value()); return false; } } // if an ancestor is paused or deferred return false std::list<const time_node*> path; get_path(path); std::list<const time_node*>::reverse_iterator it = path.rbegin(); it++; // pass over this for(;it!=path.rend();it++) { const time_node *atn = (*it); if(atn->paused() || atn->deferred()) { AM_DBG { std::string astate; if(atn->paused()) astate = "paused"; else if(atn->deferred()) astate = "deferred"; m_logger->debug("%s[%s] attempt to set_current_interval() but an ancestor is %s: %s (DT=%ld)", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), astate.c_str(), ::repr(i).c_str(), timestamp.as_doc_time_value()); } return false; } } return true;}// Add to history and invalidate the current intervalvoid time_node::played_interval(qtime_type timestamp) { m_history.push_back(m_interval); q_smil_time b(sync_node(), m_interval.begin); q_smil_time e(sync_node(), m_interval.end); m_doc_history.push_back(interval_type(b.as_doc_time(), e.as_doc_time())); m_interval = interval_type::unresolved;}// Returns the first interval played by this node.// Returns an invalid interval when this node has not played.const time_node::interval_type& time_node::get_first_interval(bool asdoc /* = false*/) const { if(asdoc) { if(!m_doc_history.empty()) return m_doc_history.front(); return interval_type::unresolved; } if(!m_history.empty()) return m_history.front(); return m_interval;}// Returns the last interval associated with this (can be invalid)const time_node::interval_type& time_node::get_last_interval() const { if(m_interval.is_valid()) return m_interval; if(!m_history.empty()) return m_history.back(); return m_interval;}// Activates the interval of this node.// This function is one of the activities executed when a node enters the active state.// See active_state::enter() function for the complete list of activities. //// timestamp: "scheduled now" in parent simple timevoid time_node::activate(qtime_type timestamp) { // verify the assumptions made in the following code assert(timestamp.first == sync_node()); if(!m_interval.contains(timestamp.second)) set_state(ts_postactive, timestamp, this); assert(timestamp.second >= 0); // We need to convert parent's simple time to this node's simple time. // For this convertion we need the dur since, // t_p = t_c + rad_c + begin_c => rad_c + t_c = t_p - begin_c // => t_c = rem(t_p - begin_c, dur) and rad_c = mod(t_p - begin_c, dur)*dur // The offset we are now within the current interval time_type ad_offset = timestamp.second - m_interval.begin; // The simple duration of this node time_type cdur = calc_dur(); // Calculate the offset within the simple duration // that this node should start playing. time_type sd_offset = 0; if(ad_offset == 0) { sd_offset = 0; } else if(!cdur.is_definite()) { sd_offset = ad_offset; } else if(cdur == 0) { sd_offset = 0; } else { sd_offset = ad_offset.rem(cdur); // In this case we need to update the values of the repeat registers. // Previous values: m_rad(0), m_precounter(0) // The current repeat index m_precounter = ad_offset.mod(cdur); // The accumulated repeat interval. m_rad = m_precounter*cdur(); } AM_DBG m_logger->debug("%s[%s].start(%ld) ST:%ld, PT:%ld, DT:%ld", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), sd_offset(), sd_offset(), timestamp.second(), timestamp.as_doc_time_value()); // Adjust timer if(m_timer) { m_timer->set_time(ad_offset()); m_timer->set_speed(m_attrs.get_speed()); } // Start node if(!paused()) { if(is_animation()) start_animation(sd_offset); else start_playable(sd_offset); if(m_timer) m_timer->resume(); }}// Starts an animationvoid time_node::start_animation(time_type offset) { qtime_type timestamp(this, offset); AM_DBG m_logger->debug("%s[%s].start_animation(%ld) DT:%ld", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), offset(), timestamp.as_doc_time_value()); animation_engine *ae = m_context->get_animation_engine(); animate_node *an = (animate_node*)this; an->prepare_interval(); ae->started(an);}// Stops an animationvoid time_node::stop_animation() { animation_engine *ae = m_context->get_animation_engine(); ae->stopped((animate_node*)this);}// Returns true when this node is associated with a playablebool time_node::is_playable() const { return !is_time_container() && !is_animation();}// Returns true when this node is an animationbool time_node::is_animation() const { return common::schema::get_instance()->is_animation(m_node->get_qname());}//////////////////////////// Playables shellvoid time_node::start_playable(time_type offset) { if(m_ffwd_mode) { AM_DBG m_logger->debug("start_playable(%ld): ffwd skip %s", offset(), get_sig().c_str()); return; } if(!is_playable() ) { return; } qtime_type timestamp(this, offset); AM_DBG m_logger->debug("%s[%s].start_playable(%ld) DT:%ld", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), offset(), timestamp.as_doc_time_value()); m_eom_flag = false; common::playable *np = create_playable(); if(np) np->wantclicks(m_want_activate_events); const lib::transition_info *trans_in = m_attrs.get_trans_in(); if(np) { if(trans_in) { m_context->start_playable(m_node, time_type_to_secs(offset()), trans_in); } else { np->start(time_type_to_secs(offset())); } } if (is_link() && m_attrs.get_actuate() == actuate_onload) { AM_DBG m_logger->debug("%s[%s].start_playable: actuate_onLoad", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); follow_link(timestamp); }}void time_node::seek_playable(time_type offset) { if(!is_playable() || m_ffwd_mode) return; AM_DBG m_logger->debug("%s[%s].seek(%ld)", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str(), offset()); m_context->seek_playable(m_node, time_type_to_secs(offset()));}void time_node::pause_playable(common::pause_display d) { if(!is_playable() || m_ffwd_mode) return; AM_DBG m_logger->debug("%s[%s].pause()", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); m_context->pause_playable(m_node, d);}void time_node::resume_playable() { if(!is_playable() || m_ffwd_mode) return; m_logger->debug("%s[%s].resume()", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); m_context->resume_playable(m_node);}void time_node::stop_playable() { if(!is_playable()) return; if(!m_needs_remove) return; m_eom_flag = true; AM_DBG m_logger->debug("%s[%s].stop()", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); m_context->stop_playable(m_node);}void time_node::repeat_playable() { if(!is_playable() || m_ffwd_mode) return; AM_DBG m_logger->debug("%s[%s].repeat()", m_attrs.get_tag().c_str(), m_attrs.get_id().c_str()); m_context->start_playable(m_node, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -