/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// transition table for restart=NEVER, fill=REMOVE staticconst StateTransitionTable stateTransitionTable_Never_Remove = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID, // active successors for FROZEN: this state is unreachable here
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED // active successors for ENDED: this state is a sink here (cannot restart)
};
// transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE staticconst StateTransitionTable stateTransitionTable_NotActive_Remove = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::ENDED, // active successors for ACTIVE: no freeze here
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID, // active successors for FROZEN: // this state is unreachable here
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: // restart possible when ended
};
// transition table for restart=ALWAYS, fill=REMOVE staticconst StateTransitionTable stateTransitionTable_Always_Remove = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: restart
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID, // active successors for FROZEN: // this state is unreachable here
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
};
// transition table for restart=NEVER, fill=FREEZE staticconst StateTransitionTable stateTransitionTable_Never_Freeze = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED, // active successors for FROZEN: end
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED, // active successors for ENDED: this state is a sink here (cannot restart)
};
// transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE staticconst StateTransitionTable stateTransitionTable_NotActive_Freeze = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: // restart possible when ended
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: // restart possible when ended
};
// transition table for restart=ALWAYS, fill=FREEZE staticconst StateTransitionTable stateTransitionTable_Always_Freeze = {
AnimationNode::INVALID,
AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED
AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED
AnimationNode::INVALID,
AnimationNode::FROZEN|AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: // end object, restart
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: restart possible
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::INVALID,
AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart
};
int nRestartValue; switch( nRestartMode ) { default: case animations::AnimationRestart::DEFAULT: // same value: animations::AnimationRestart::INHERIT:
OSL_FAIL( "getStateTransitionTable(): unexpected case for restart" );
[[fallthrough]]; case animations::AnimationRestart::NEVER:
nRestartValue = 0; break; case animations::AnimationRestart::WHEN_NOT_ACTIVE:
nRestartValue = 1; break; case animations::AnimationRestart::ALWAYS:
nRestartValue = 2; break;
}
int nFillValue; switch( nFillMode ) { default: case animations::AnimationFill::AUTO: case animations::AnimationFill::DEFAULT: // same value: animations::AnimationFill::INHERIT:
OSL_FAIL( "getStateTransitionTable(): unexpected case for fill" );
[[fallthrough]]; case animations::AnimationFill::REMOVE:
nFillValue = 0; break; case animations::AnimationFill::FREEZE: case animations::AnimationFill::HOLD: case animations::AnimationFill::TRANSITION:
nFillValue = 1; break;
}
// For AUTO fill mode, SMIL specifies that fill mode is FREEZE, // if no explicit active duration is given // (no duration, end, repeatCount or repeatDuration given), // and REMOVE otherwise if( nFill == animations::AnimationFill::AUTO ) { return (isIndefiniteTiming( mxAnimationNode->getDuration() ) &&
isIndefiniteTiming( mxAnimationNode->getEnd() ) &&
!mxAnimationNode->getRepeatCount().hasValue() &&
isIndefiniteTiming( mxAnimationNode->getRepeatDuration() ))
? animations::AnimationFill::FREEZE
: animations::AnimationFill::REMOVE;
} else { return nFill;
}
}
bool BaseNode::init()
{ if (! checkValidNode()) returnfalse;
meCurrState = UNRESOLVED; // discharge a loaded event, if any: if (mpCurrentEvent) {
mpCurrentEvent->dispose();
mpCurrentEvent.reset();
} return init_st(); // may call derived class
}
bool BaseNode::init_st()
{ returntrue;
}
bool BaseNode::resolve()
{ if (! checkValidNode()) returnfalse;
OSL_ASSERT( meCurrState != RESOLVED ); if (inStateOrTransition( RESOLVED )) returntrue;
StateTransition st(this); if (st.enter( RESOLVED ) &&
isTransition( RESOLVED, ACTIVE ) &&
resolve_st() /* may call derived class */)
{
st.commit(); // changing state
// discharge a loaded event, if any: if (mpCurrentEvent)
mpCurrentEvent->dispose();
// schedule activation event:
// This method takes the NodeContext::mnStartDelay value into account, // to cater for iterate container time shifts. We cannot put different // iterations of the iterate container's children into different // subcontainer (such as a 'DelayContainer', which delays resolving its // children by a fixed amount), since all iterations' nodes must be // resolved at the same time (otherwise, the delayed subset creation // will not work, i.e. deactivate the subsets too late in the master // shape).
uno::Any const aBegin( mxAnimationNode->getBegin() ); if (aBegin.hasValue()) { auto self(mpSelf);
mpCurrentEvent = generateEvent(
aBegin, [self=std::move(self)] () { self->activate(); },
maContext, mnStartDelay );
} else { // For some leaf nodes, PPT import yields empty begin time, // although semantically, it should be 0.0 // TODO(F3): That should really be provided by the PPT import
// schedule delayed activation event. Take iterate node // timeout into account auto self(mpSelf);
mpCurrentEvent = makeDelay(
[self=std::move(self)] () { self->activate(); },
mnStartDelay,
u"AnimationNode::activate with delay"_ustr);
maContext.mrEventQueue.addEvent( mpCurrentEvent );
}
returntrue;
} returnfalse;
}
bool BaseNode::resolve_st()
{ returntrue;
}
void BaseNode::activate()
{ if (! checkValidNode()) return;
OSL_ASSERT( meCurrState != ACTIVE ); if (inStateOrTransition( ACTIVE )) return;
StateTransition st(this); if (st.enter( ACTIVE )) {
void BaseNode::scheduleDeactivationEvent( EventSharedPtr const& pEvent )
{ if (mpCurrentEvent) {
mpCurrentEvent->dispose();
mpCurrentEvent.reset();
} if (pEvent) { if (maContext.mrEventQueue.addEvent( pEvent ))
mpCurrentEvent = pEvent;
} else { // This method need not take the // NodeContext::mnStartDelay value into account, // because the deactivation event is only scheduled // when the effect is started: the timeout is then // already respected.
// xxx todo: // think about set node, anim base node! // if anim base node has no activity, this is called to schedule deactivation, // but what if it does not schedule anything?
if (mxAnimationNode->getEnd().hasValue())
{ // TODO: We may need to calculate the duration if the end value is numeric. // We expect that the end value contains EventTrigger::ON_NEXT here. // LibreOffice does not generate numeric values, so we can leave it // until we find a test case.
mpCurrentEvent = generateEvent(
mxAnimationNode->getEnd(),
[self=mpSelf] () { self->deactivate(); },
maContext, 0.0 );
if (isTransition( meCurrState, FROZEN, false/* no OSL_ASSERT */ )) { // do transition to FROZEN:
StateTransition st(this); if (st.enter( FROZEN, StateTransition::Options::FORCE )) {
deactivate_st( FROZEN );
st.commit();
notifyEndListeners();
// discharge a loaded event, before going on: if (mpCurrentEvent) {
mpCurrentEvent->dispose();
mpCurrentEvent.reset();
}
}
} else { // use end instead:
end();
} // state has changed either to FROZEN or ENDED
}
// END must always be reachable. If not, that's an error in the // transition tables
OSL_ENSURE( isTransition( meCurrState, ENDED ), "end state not reachable in transition table" );
StateTransition st(this); if (!st.enter( ENDED, StateTransition::Options::FORCE )) return;
deactivate_st( ENDED );
st.commit(); // changing state
// if is FROZEN or is to be FROZEN, then // will/already notified deactivating listeners if (!bIsFrozenOrInTransitionToFrozen)
notifyEndListeners();
// discharge a loaded event, before going on: if (mpCurrentEvent) {
mpCurrentEvent->dispose();
mpCurrentEvent.reset();
}
}
void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier )
{
OSL_ASSERT( rNotifier->getState() == FROZEN ||
rNotifier->getState() == ENDED ); // TODO(F1): for end sync functionality, this might indeed be used some day
}
// notify state change
maContext.mrEventMultiplexer.notifyAnimationEnd( mpSelf );
// notify main sequence end (iff we're the main // sequence root node). This is because the main // sequence determines the active duration of the // slide. All other sequences are secondary, in that // they don't prevent a slide change from happening, // even if they have not been completed. In other // words, all sequences except the main sequence are // optional for the slide lifetime. if (isMainSequenceRootNode())
maContext.mrEventMultiplexer.notifySlideAnimationsEnd();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.