1*70f497fbSAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*70f497fbSAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*70f497fbSAndrew Rist * or more contributor license agreements. See the NOTICE file 5*70f497fbSAndrew Rist * distributed with this work for additional information 6*70f497fbSAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*70f497fbSAndrew Rist * to you under the Apache License, Version 2.0 (the 8*70f497fbSAndrew Rist * "License"); you may not use this file except in compliance 9*70f497fbSAndrew Rist * with the License. You may obtain a copy of the License at 10cdf0e10cSrcweir * 11*70f497fbSAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12cdf0e10cSrcweir * 13*70f497fbSAndrew Rist * Unless required by applicable law or agreed to in writing, 14*70f497fbSAndrew Rist * software distributed under the License is distributed on an 15*70f497fbSAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*70f497fbSAndrew Rist * KIND, either express or implied. See the License for the 17*70f497fbSAndrew Rist * specific language governing permissions and limitations 18*70f497fbSAndrew Rist * under the License. 19cdf0e10cSrcweir * 20*70f497fbSAndrew Rist *************************************************************/ 21*70f497fbSAndrew Rist 22*70f497fbSAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 25cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 26cdf0e10cSrcweir 27cdf0e10cSrcweir // must be first 28cdf0e10cSrcweir #include <canvas/debug.hxx> 29cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 30cdf0e10cSrcweir 31cdf0e10cSrcweir #include <com/sun/star/animations/XAnimate.hpp> 32cdf0e10cSrcweir #include <com/sun/star/presentation/ParagraphTarget.hpp> 33cdf0e10cSrcweir #include <com/sun/star/animations/AnimationFill.hpp> 34cdf0e10cSrcweir #include <com/sun/star/animations/AnimationRestart.hpp> 35cdf0e10cSrcweir #include <com/sun/star/presentation/EffectNodeType.hpp> 36cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp> 37cdf0e10cSrcweir 38cdf0e10cSrcweir #include "basenode.hxx" 39cdf0e10cSrcweir #include "eventmultiplexer.hxx" 40cdf0e10cSrcweir #include "basecontainernode.hxx" 41cdf0e10cSrcweir #include "eventqueue.hxx" 42cdf0e10cSrcweir #include "delayevent.hxx" 43cdf0e10cSrcweir #include "tools.hxx" 44cdf0e10cSrcweir #include "nodetools.hxx" 45cdf0e10cSrcweir #include "generateevent.hxx" 46cdf0e10cSrcweir #include "debug.hxx" 47cdf0e10cSrcweir 48cdf0e10cSrcweir #include <boost/bind.hpp> 49cdf0e10cSrcweir #include <vector> 50cdf0e10cSrcweir #include <algorithm> 51cdf0e10cSrcweir #include <iterator> 52cdf0e10cSrcweir 53cdf0e10cSrcweir using namespace ::com::sun::star; 54cdf0e10cSrcweir 55cdf0e10cSrcweir namespace slideshow { 56cdf0e10cSrcweir namespace internal { 57cdf0e10cSrcweir 58cdf0e10cSrcweir namespace { 59cdf0e10cSrcweir 60cdf0e10cSrcweir typedef int StateTransitionTable[17]; 61cdf0e10cSrcweir 62cdf0e10cSrcweir // State transition tables 63cdf0e10cSrcweir // ========================================================================= 64cdf0e10cSrcweir 65cdf0e10cSrcweir const int* getStateTransitionTable( sal_Int16 nRestartMode, 66cdf0e10cSrcweir sal_Int16 nFillMode ) 67cdf0e10cSrcweir { 68cdf0e10cSrcweir // TODO(F2): restart issues in below tables 69cdf0e10cSrcweir 70cdf0e10cSrcweir // transition table for restart=NEVER, fill=REMOVE 71cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_Never_Remove = { 72cdf0e10cSrcweir AnimationNode::INVALID, 73cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 74cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 75cdf0e10cSrcweir AnimationNode::INVALID, 76cdf0e10cSrcweir AnimationNode::ENDED, // active successors for ACTIVE: no freeze here 77cdf0e10cSrcweir AnimationNode::INVALID, 78cdf0e10cSrcweir AnimationNode::INVALID, 79cdf0e10cSrcweir AnimationNode::INVALID, 80cdf0e10cSrcweir AnimationNode::INVALID, // active successors for FROZEN: this state is unreachable here 81cdf0e10cSrcweir AnimationNode::INVALID, 82cdf0e10cSrcweir AnimationNode::INVALID, 83cdf0e10cSrcweir AnimationNode::INVALID, 84cdf0e10cSrcweir AnimationNode::INVALID, 85cdf0e10cSrcweir AnimationNode::INVALID, 86cdf0e10cSrcweir AnimationNode::INVALID, 87cdf0e10cSrcweir AnimationNode::INVALID, 88cdf0e10cSrcweir AnimationNode::ENDED // active successors for ENDED: this state is a sink here (cannot restart) 89cdf0e10cSrcweir }; 90cdf0e10cSrcweir 91cdf0e10cSrcweir // transition table for restart=WHEN_NOT_ACTIVE, fill=REMOVE 92cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_NotActive_Remove = { 93cdf0e10cSrcweir AnimationNode::INVALID, 94cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 95cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 96cdf0e10cSrcweir AnimationNode::INVALID, 97cdf0e10cSrcweir AnimationNode::ENDED, // active successors for ACTIVE: no freeze here 98cdf0e10cSrcweir AnimationNode::INVALID, 99cdf0e10cSrcweir AnimationNode::INVALID, 100cdf0e10cSrcweir AnimationNode::INVALID, 101cdf0e10cSrcweir AnimationNode::INVALID, // active successors for FROZEN: 102cdf0e10cSrcweir // this state is unreachable here 103cdf0e10cSrcweir AnimationNode::INVALID, 104cdf0e10cSrcweir AnimationNode::INVALID, 105cdf0e10cSrcweir AnimationNode::INVALID, 106cdf0e10cSrcweir AnimationNode::INVALID, 107cdf0e10cSrcweir AnimationNode::INVALID, 108cdf0e10cSrcweir AnimationNode::INVALID, 109cdf0e10cSrcweir AnimationNode::INVALID, 110cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: 111cdf0e10cSrcweir // restart possible when ended 112cdf0e10cSrcweir }; 113cdf0e10cSrcweir 114cdf0e10cSrcweir // transition table for restart=ALWAYS, fill=REMOVE 115cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_Always_Remove = { 116cdf0e10cSrcweir AnimationNode::INVALID, 117cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 118cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 119cdf0e10cSrcweir AnimationNode::INVALID, 120cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: restart 121cdf0e10cSrcweir AnimationNode::INVALID, 122cdf0e10cSrcweir AnimationNode::INVALID, 123cdf0e10cSrcweir AnimationNode::INVALID, 124cdf0e10cSrcweir AnimationNode::INVALID, // active successors for FROZEN: 125cdf0e10cSrcweir // this state is unreachable here 126cdf0e10cSrcweir AnimationNode::INVALID, 127cdf0e10cSrcweir AnimationNode::INVALID, 128cdf0e10cSrcweir AnimationNode::INVALID, 129cdf0e10cSrcweir AnimationNode::INVALID, 130cdf0e10cSrcweir AnimationNode::INVALID, 131cdf0e10cSrcweir AnimationNode::INVALID, 132cdf0e10cSrcweir AnimationNode::INVALID, 133cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart 134cdf0e10cSrcweir }; 135cdf0e10cSrcweir 136cdf0e10cSrcweir // transition table for restart=NEVER, fill=FREEZE 137cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_Never_Freeze = { 138cdf0e10cSrcweir AnimationNode::INVALID, 139cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 140cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 141cdf0e10cSrcweir AnimationNode::INVALID, 142cdf0e10cSrcweir AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object 143cdf0e10cSrcweir AnimationNode::INVALID, 144cdf0e10cSrcweir AnimationNode::INVALID, 145cdf0e10cSrcweir AnimationNode::INVALID, 146cdf0e10cSrcweir AnimationNode::ENDED, // active successors for FROZEN: end 147cdf0e10cSrcweir AnimationNode::INVALID, 148cdf0e10cSrcweir AnimationNode::INVALID, 149cdf0e10cSrcweir AnimationNode::INVALID, 150cdf0e10cSrcweir AnimationNode::INVALID, 151cdf0e10cSrcweir AnimationNode::INVALID, 152cdf0e10cSrcweir AnimationNode::INVALID, 153cdf0e10cSrcweir AnimationNode::INVALID, 154cdf0e10cSrcweir AnimationNode::ENDED, // active successors for ENDED: this state is a sink here (cannot restart) 155cdf0e10cSrcweir }; 156cdf0e10cSrcweir 157cdf0e10cSrcweir // transition table for restart=WHEN_NOT_ACTIVE, fill=FREEZE 158cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_NotActive_Freeze = { 159cdf0e10cSrcweir AnimationNode::INVALID, 160cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 161cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 162cdf0e10cSrcweir AnimationNode::INVALID, 163cdf0e10cSrcweir AnimationNode::FROZEN|AnimationNode::ENDED, // active successors for ACTIVE: freeze object 164cdf0e10cSrcweir AnimationNode::INVALID, 165cdf0e10cSrcweir AnimationNode::INVALID, 166cdf0e10cSrcweir AnimationNode::INVALID, 167cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: 168cdf0e10cSrcweir // restart possible when ended 169cdf0e10cSrcweir AnimationNode::INVALID, 170cdf0e10cSrcweir AnimationNode::INVALID, 171cdf0e10cSrcweir AnimationNode::INVALID, 172cdf0e10cSrcweir AnimationNode::INVALID, 173cdf0e10cSrcweir AnimationNode::INVALID, 174cdf0e10cSrcweir AnimationNode::INVALID, 175cdf0e10cSrcweir AnimationNode::INVALID, 176cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE // active successors for ENDED: 177cdf0e10cSrcweir // restart possible when ended 178cdf0e10cSrcweir }; 179cdf0e10cSrcweir 180cdf0e10cSrcweir // transition table for restart=ALWAYS, fill=FREEZE 181cdf0e10cSrcweir static const StateTransitionTable stateTransitionTable_Always_Freeze = { 182cdf0e10cSrcweir AnimationNode::INVALID, 183cdf0e10cSrcweir AnimationNode::RESOLVED|AnimationNode::ENDED, // active successors for UNRESOLVED 184cdf0e10cSrcweir AnimationNode::ACTIVE|AnimationNode::ENDED, // active successors for RESOLVED 185cdf0e10cSrcweir AnimationNode::INVALID, 186cdf0e10cSrcweir AnimationNode::FROZEN|AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED, // active successors for ACTIVE: 187cdf0e10cSrcweir // end object, restart 188cdf0e10cSrcweir AnimationNode::INVALID, 189cdf0e10cSrcweir AnimationNode::INVALID, 190cdf0e10cSrcweir AnimationNode::INVALID, 191cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::RESOLVED|AnimationNode::ACTIVE, // active successors for FROZEN: restart possible 192cdf0e10cSrcweir AnimationNode::INVALID, 193cdf0e10cSrcweir AnimationNode::INVALID, 194cdf0e10cSrcweir AnimationNode::INVALID, 195cdf0e10cSrcweir AnimationNode::INVALID, 196cdf0e10cSrcweir AnimationNode::INVALID, 197cdf0e10cSrcweir AnimationNode::INVALID, 198cdf0e10cSrcweir AnimationNode::INVALID, 199cdf0e10cSrcweir AnimationNode::ENDED|AnimationNode::ACTIVE|AnimationNode::RESOLVED // active successors for ENDED: restart 200cdf0e10cSrcweir }; 201cdf0e10cSrcweir 202cdf0e10cSrcweir static const StateTransitionTable* tableGuide[] = { 203cdf0e10cSrcweir &stateTransitionTable_Never_Remove, 204cdf0e10cSrcweir &stateTransitionTable_NotActive_Remove, 205cdf0e10cSrcweir &stateTransitionTable_Always_Remove, 206cdf0e10cSrcweir &stateTransitionTable_Never_Freeze, 207cdf0e10cSrcweir &stateTransitionTable_NotActive_Freeze, 208cdf0e10cSrcweir &stateTransitionTable_Always_Freeze 209cdf0e10cSrcweir }; 210cdf0e10cSrcweir 211cdf0e10cSrcweir int nRestartValue; 212cdf0e10cSrcweir switch( nRestartMode ) { 213cdf0e10cSrcweir default: 214cdf0e10cSrcweir case animations::AnimationRestart::DEFAULT: 215cdf0e10cSrcweir // same value: animations::AnimationRestart::INHERIT: 216cdf0e10cSrcweir OSL_ENSURE( 217cdf0e10cSrcweir false, "getStateTransitionTable(): unexpected case for restart" ); 218cdf0e10cSrcweir // FALLTHROUGH intended 219cdf0e10cSrcweir case animations::AnimationRestart::NEVER: 220cdf0e10cSrcweir nRestartValue = 0; 221cdf0e10cSrcweir break; 222cdf0e10cSrcweir case animations::AnimationRestart::WHEN_NOT_ACTIVE: 223cdf0e10cSrcweir nRestartValue = 1; 224cdf0e10cSrcweir break; 225cdf0e10cSrcweir case animations::AnimationRestart::ALWAYS: 226cdf0e10cSrcweir nRestartValue = 2; 227cdf0e10cSrcweir break; 228cdf0e10cSrcweir } 229cdf0e10cSrcweir 230cdf0e10cSrcweir int nFillValue; 231cdf0e10cSrcweir switch( nFillMode ) { 232cdf0e10cSrcweir default: 233cdf0e10cSrcweir case animations::AnimationFill::AUTO: 234cdf0e10cSrcweir case animations::AnimationFill::DEFAULT: 235cdf0e10cSrcweir // same value: animations::AnimationFill::INHERIT: 236cdf0e10cSrcweir OSL_ENSURE( 237cdf0e10cSrcweir false, "getStateTransitionTable(): unexpected case for fill" ); 238cdf0e10cSrcweir // FALLTHROUGH intended 239cdf0e10cSrcweir case animations::AnimationFill::REMOVE: 240cdf0e10cSrcweir nFillValue = 0; 241cdf0e10cSrcweir break; 242cdf0e10cSrcweir case animations::AnimationFill::FREEZE: 243cdf0e10cSrcweir case animations::AnimationFill::HOLD: 244cdf0e10cSrcweir case animations::AnimationFill::TRANSITION: 245cdf0e10cSrcweir nFillValue = 1; 246cdf0e10cSrcweir break; 247cdf0e10cSrcweir } 248cdf0e10cSrcweir 249cdf0e10cSrcweir return *tableGuide[ 3*nFillValue + nRestartValue ]; 250cdf0e10cSrcweir } 251cdf0e10cSrcweir 252cdf0e10cSrcweir /// Little helper predicate, to detect main sequence root node 253cdf0e10cSrcweir bool isMainSequenceRootNode_( 254cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xNode ) 255cdf0e10cSrcweir { 256cdf0e10cSrcweir // detect main sequence root node (need that for 257cdf0e10cSrcweir // end-of-mainsequence signalling below) 258cdf0e10cSrcweir beans::NamedValue const aSearchKey( 259cdf0e10cSrcweir rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "node-type" ) ), 260cdf0e10cSrcweir uno::makeAny( presentation::EffectNodeType::MAIN_SEQUENCE ) ); 261cdf0e10cSrcweir 262cdf0e10cSrcweir uno::Sequence<beans::NamedValue> const userData(xNode->getUserData()); 263cdf0e10cSrcweir return findNamedValue( userData, aSearchKey ); 264cdf0e10cSrcweir } 265cdf0e10cSrcweir 266cdf0e10cSrcweir } // anon namespace 267cdf0e10cSrcweir 268cdf0e10cSrcweir // BaseNode implementation 269cdf0e10cSrcweir //========================================================================= 270cdf0e10cSrcweir 271cdf0e10cSrcweir /** state transition handling 272cdf0e10cSrcweir */ 273cdf0e10cSrcweir class BaseNode::StateTransition : private boost::noncopyable 274cdf0e10cSrcweir { 275cdf0e10cSrcweir public: 276cdf0e10cSrcweir enum Options { NONE, FORCE }; 277cdf0e10cSrcweir 278cdf0e10cSrcweir explicit StateTransition( BaseNode * pNode ) 279cdf0e10cSrcweir : mpNode(pNode), meToState(INVALID) {} 280cdf0e10cSrcweir 281cdf0e10cSrcweir ~StateTransition() { 282cdf0e10cSrcweir clear(); 283cdf0e10cSrcweir } 284cdf0e10cSrcweir 285cdf0e10cSrcweir bool enter( NodeState eToState, int options = NONE ) 286cdf0e10cSrcweir { 287cdf0e10cSrcweir OSL_ENSURE( meToState == INVALID, 288cdf0e10cSrcweir "### commit() before enter()ing again!" ); 289cdf0e10cSrcweir if (meToState != INVALID) 290cdf0e10cSrcweir return false; 291cdf0e10cSrcweir bool const bForce = ((options & FORCE) != 0); 292cdf0e10cSrcweir if (!bForce && !mpNode->isTransition( mpNode->meCurrState, eToState )) 293cdf0e10cSrcweir return false; 294cdf0e10cSrcweir // recursion detection: 295cdf0e10cSrcweir if ((mpNode->meCurrentStateTransition & eToState) != 0) 296cdf0e10cSrcweir return false; // already in wanted transition 297cdf0e10cSrcweir // mark transition: 298cdf0e10cSrcweir mpNode->meCurrentStateTransition |= eToState; 299cdf0e10cSrcweir meToState = eToState; 300cdf0e10cSrcweir return true; // in transition 301cdf0e10cSrcweir } 302cdf0e10cSrcweir 303cdf0e10cSrcweir void commit() { 304cdf0e10cSrcweir OSL_ENSURE( meToState != INVALID, "### nothing to commit!" ); 305cdf0e10cSrcweir if (meToState != INVALID) { 306cdf0e10cSrcweir mpNode->meCurrState = meToState; 307cdf0e10cSrcweir clear(); 308cdf0e10cSrcweir } 309cdf0e10cSrcweir 310cdf0e10cSrcweir // Uncomment the following line to write the node tree to file on 311cdf0e10cSrcweir // every state change of one of its nodes. 312cdf0e10cSrcweir // Debug_ShowNodeTree(mpNode->mpSelf); 313cdf0e10cSrcweir } 314cdf0e10cSrcweir 315cdf0e10cSrcweir void clear() { 316cdf0e10cSrcweir if (meToState != INVALID) { 317cdf0e10cSrcweir OSL_ASSERT( (mpNode->meCurrentStateTransition & meToState) != 0 ); 318cdf0e10cSrcweir mpNode->meCurrentStateTransition &= ~meToState; 319cdf0e10cSrcweir meToState = INVALID; 320cdf0e10cSrcweir } 321cdf0e10cSrcweir } 322cdf0e10cSrcweir 323cdf0e10cSrcweir private: 324cdf0e10cSrcweir BaseNode *const mpNode; 325cdf0e10cSrcweir NodeState meToState; 326cdf0e10cSrcweir }; 327cdf0e10cSrcweir 328cdf0e10cSrcweir BaseNode::BaseNode( const uno::Reference< animations::XAnimationNode >& xNode, 329cdf0e10cSrcweir const BaseContainerNodeSharedPtr& rParent, 330cdf0e10cSrcweir const NodeContext& rContext ) : 331cdf0e10cSrcweir maContext( rContext.maContext ), 332cdf0e10cSrcweir maDeactivatingListeners(), 333cdf0e10cSrcweir mxAnimationNode( xNode ), 334cdf0e10cSrcweir mpParent( rParent ), 335cdf0e10cSrcweir mpSelf(), 336cdf0e10cSrcweir mpStateTransitionTable( NULL ), 337cdf0e10cSrcweir mnStartDelay( rContext.mnStartDelay ), 338cdf0e10cSrcweir meCurrState( UNRESOLVED ), 339cdf0e10cSrcweir meCurrentStateTransition( 0 ), 340cdf0e10cSrcweir mpCurrentEvent(), 341cdf0e10cSrcweir mbIsMainSequenceRootNode( isMainSequenceRootNode_( xNode ) ) 342cdf0e10cSrcweir { 343cdf0e10cSrcweir ENSURE_OR_THROW( mxAnimationNode.is(), 344cdf0e10cSrcweir "BaseNode::BaseNode(): Invalid XAnimationNode" ); 345cdf0e10cSrcweir 346cdf0e10cSrcweir // setup state transition table 347cdf0e10cSrcweir mpStateTransitionTable = getStateTransitionTable( getRestartMode(), 348cdf0e10cSrcweir getFillMode() ); 349cdf0e10cSrcweir } 350cdf0e10cSrcweir 351cdf0e10cSrcweir void BaseNode::dispose() 352cdf0e10cSrcweir { 353cdf0e10cSrcweir meCurrState = INVALID; 354cdf0e10cSrcweir 355cdf0e10cSrcweir // discharge a loaded event, if any: 356cdf0e10cSrcweir if (mpCurrentEvent) { 357cdf0e10cSrcweir mpCurrentEvent->dispose(); 358cdf0e10cSrcweir mpCurrentEvent.reset(); 359cdf0e10cSrcweir } 360cdf0e10cSrcweir maDeactivatingListeners.clear(); 361cdf0e10cSrcweir mxAnimationNode.clear(); 362cdf0e10cSrcweir mpParent.reset(); 363cdf0e10cSrcweir mpSelf.reset(); 364cdf0e10cSrcweir maContext.dispose(); 365cdf0e10cSrcweir } 366cdf0e10cSrcweir 367cdf0e10cSrcweir 368cdf0e10cSrcweir sal_Int16 BaseNode::getRestartMode() 369cdf0e10cSrcweir { 370cdf0e10cSrcweir const sal_Int16 nTmp( mxAnimationNode->getRestart() ); 371cdf0e10cSrcweir return (nTmp != animations::AnimationRestart::DEFAULT && 372cdf0e10cSrcweir nTmp != animations::AnimationRestart::INHERIT) 373cdf0e10cSrcweir ? nTmp : getRestartDefaultMode(); 374cdf0e10cSrcweir } 375cdf0e10cSrcweir 376cdf0e10cSrcweir sal_Int16 BaseNode::getFillMode() 377cdf0e10cSrcweir { 378cdf0e10cSrcweir const sal_Int16 nTmp( mxAnimationNode->getFill() ); 379cdf0e10cSrcweir const sal_Int16 nFill((nTmp != animations::AnimationFill::DEFAULT && 380cdf0e10cSrcweir nTmp != animations::AnimationFill::INHERIT) 381cdf0e10cSrcweir ? nTmp : getFillDefaultMode()); 382cdf0e10cSrcweir 383cdf0e10cSrcweir // For AUTO fill mode, SMIL specifies that fill mode is FREEZE, 384cdf0e10cSrcweir // if no explicit active duration is given 385cdf0e10cSrcweir // (no duration, end, repeatCount or repeatDuration given), 386cdf0e10cSrcweir // and REMOVE otherwise 387cdf0e10cSrcweir if( nFill == animations::AnimationFill::AUTO ) { 388cdf0e10cSrcweir return (isIndefiniteTiming( mxAnimationNode->getDuration() ) && 389cdf0e10cSrcweir isIndefiniteTiming( mxAnimationNode->getEnd() ) && 390cdf0e10cSrcweir !mxAnimationNode->getRepeatCount().hasValue() && 391cdf0e10cSrcweir isIndefiniteTiming( mxAnimationNode->getRepeatDuration() )) 392cdf0e10cSrcweir ? animations::AnimationFill::FREEZE 393cdf0e10cSrcweir : animations::AnimationFill::REMOVE; 394cdf0e10cSrcweir } 395cdf0e10cSrcweir else { 396cdf0e10cSrcweir return nFill; 397cdf0e10cSrcweir } 398cdf0e10cSrcweir } 399cdf0e10cSrcweir 400cdf0e10cSrcweir sal_Int16 BaseNode::getFillDefaultMode() const 401cdf0e10cSrcweir { 402cdf0e10cSrcweir sal_Int16 nFillDefault = mxAnimationNode->getFillDefault(); 403cdf0e10cSrcweir if (nFillDefault == animations::AnimationFill::DEFAULT) { 404cdf0e10cSrcweir nFillDefault = (mpParent != 0 405cdf0e10cSrcweir ? mpParent->getFillDefaultMode() 406cdf0e10cSrcweir : animations::AnimationFill::AUTO); 407cdf0e10cSrcweir } 408cdf0e10cSrcweir return nFillDefault; 409cdf0e10cSrcweir } 410cdf0e10cSrcweir 411cdf0e10cSrcweir sal_Int16 BaseNode::getRestartDefaultMode() const 412cdf0e10cSrcweir { 413cdf0e10cSrcweir sal_Int16 nRestartDefaultMode = mxAnimationNode->getRestartDefault(); 414cdf0e10cSrcweir if (nRestartDefaultMode == animations::AnimationRestart::DEFAULT) { 415cdf0e10cSrcweir nRestartDefaultMode = (mpParent != 0 416cdf0e10cSrcweir ? mpParent->getRestartDefaultMode() 417cdf0e10cSrcweir : animations::AnimationRestart::ALWAYS); 418cdf0e10cSrcweir } 419cdf0e10cSrcweir return nRestartDefaultMode; 420cdf0e10cSrcweir } 421cdf0e10cSrcweir 422cdf0e10cSrcweir uno::Reference<animations::XAnimationNode> BaseNode::getXAnimationNode() const 423cdf0e10cSrcweir { 424cdf0e10cSrcweir return mxAnimationNode; 425cdf0e10cSrcweir } 426cdf0e10cSrcweir 427cdf0e10cSrcweir bool BaseNode::init() 428cdf0e10cSrcweir { 429cdf0e10cSrcweir if (! checkValidNode()) 430cdf0e10cSrcweir return false; 431cdf0e10cSrcweir meCurrState = UNRESOLVED; 432cdf0e10cSrcweir // discharge a loaded event, if any: 433cdf0e10cSrcweir if (mpCurrentEvent) { 434cdf0e10cSrcweir mpCurrentEvent->dispose(); 435cdf0e10cSrcweir mpCurrentEvent.reset(); 436cdf0e10cSrcweir } 437cdf0e10cSrcweir return init_st(); // may call derived class 438cdf0e10cSrcweir } 439cdf0e10cSrcweir 440cdf0e10cSrcweir bool BaseNode::init_st() 441cdf0e10cSrcweir { 442cdf0e10cSrcweir return true; 443cdf0e10cSrcweir } 444cdf0e10cSrcweir 445cdf0e10cSrcweir bool BaseNode::resolve() 446cdf0e10cSrcweir { 447cdf0e10cSrcweir if (! checkValidNode()) 448cdf0e10cSrcweir return false; 449cdf0e10cSrcweir 450cdf0e10cSrcweir OSL_ASSERT( meCurrState != RESOLVED ); 451cdf0e10cSrcweir if (inStateOrTransition( RESOLVED )) 452cdf0e10cSrcweir return true; 453cdf0e10cSrcweir 454cdf0e10cSrcweir StateTransition st(this); 455cdf0e10cSrcweir if (st.enter( RESOLVED ) && 456cdf0e10cSrcweir isTransition( RESOLVED, ACTIVE ) && 457cdf0e10cSrcweir resolve_st() /* may call derived class */) 458cdf0e10cSrcweir { 459cdf0e10cSrcweir st.commit(); // changing state 460cdf0e10cSrcweir 461cdf0e10cSrcweir // discharge a loaded event, if any: 462cdf0e10cSrcweir if (mpCurrentEvent) 463cdf0e10cSrcweir mpCurrentEvent->dispose(); 464cdf0e10cSrcweir 465cdf0e10cSrcweir // schedule activation event: 466cdf0e10cSrcweir 467cdf0e10cSrcweir // This method takes the NodeContext::mnStartDelay value into account, 468cdf0e10cSrcweir // to cater for iterate container time shifts. We cannot put different 469cdf0e10cSrcweir // iterations of the iterate container's children into different 470cdf0e10cSrcweir // subcontainer (such as a 'DelayContainer', which delays resolving its 471cdf0e10cSrcweir // children by a fixed amount), since all iterations' nodes must be 472cdf0e10cSrcweir // resolved at the same time (otherwise, the delayed subset creation 473cdf0e10cSrcweir // will not work, i.e. deactivate the subsets too late in the master 474cdf0e10cSrcweir // shape). 475cdf0e10cSrcweir uno::Any const aBegin( mxAnimationNode->getBegin() ); 476cdf0e10cSrcweir if (aBegin.hasValue()) { 477cdf0e10cSrcweir mpCurrentEvent = generateEvent( 478cdf0e10cSrcweir aBegin, boost::bind( &AnimationNode::activate, mpSelf ), 479cdf0e10cSrcweir maContext, mnStartDelay ); 480cdf0e10cSrcweir } 481cdf0e10cSrcweir else { 482cdf0e10cSrcweir // For some leaf nodes, PPT import yields empty begin time, 483cdf0e10cSrcweir // although semantically, it should be 0.0 484cdf0e10cSrcweir // TODO(F3): That should really be provided by the PPT import 485cdf0e10cSrcweir 486cdf0e10cSrcweir // schedule delayed activation event. Take iterate node 487cdf0e10cSrcweir // timeout into account 488cdf0e10cSrcweir mpCurrentEvent = makeDelay( 489cdf0e10cSrcweir boost::bind( &AnimationNode::activate, mpSelf ), 490cdf0e10cSrcweir mnStartDelay, 491cdf0e10cSrcweir "AnimationNode::activate with delay"); 492cdf0e10cSrcweir maContext.mrEventQueue.addEvent( mpCurrentEvent ); 493cdf0e10cSrcweir } 494cdf0e10cSrcweir 495cdf0e10cSrcweir return true; 496cdf0e10cSrcweir } 497cdf0e10cSrcweir return false; 498cdf0e10cSrcweir } 499cdf0e10cSrcweir 500cdf0e10cSrcweir bool BaseNode::resolve_st() 501cdf0e10cSrcweir { 502cdf0e10cSrcweir return true; 503cdf0e10cSrcweir } 504cdf0e10cSrcweir 505cdf0e10cSrcweir 506cdf0e10cSrcweir bool BaseNode::activate() 507cdf0e10cSrcweir { 508cdf0e10cSrcweir if (! checkValidNode()) 509cdf0e10cSrcweir return false; 510cdf0e10cSrcweir 511cdf0e10cSrcweir OSL_ASSERT( meCurrState != ACTIVE ); 512cdf0e10cSrcweir if (inStateOrTransition( ACTIVE )) 513cdf0e10cSrcweir return true; 514cdf0e10cSrcweir 515cdf0e10cSrcweir StateTransition st(this); 516cdf0e10cSrcweir if (st.enter( ACTIVE )) { 517cdf0e10cSrcweir 518cdf0e10cSrcweir activate_st(); // calling derived class 519cdf0e10cSrcweir 520cdf0e10cSrcweir st.commit(); // changing state 521cdf0e10cSrcweir 522cdf0e10cSrcweir maContext.mrEventMultiplexer.notifyAnimationStart( mpSelf ); 523cdf0e10cSrcweir 524cdf0e10cSrcweir return true; 525cdf0e10cSrcweir } 526cdf0e10cSrcweir 527cdf0e10cSrcweir return false; 528cdf0e10cSrcweir } 529cdf0e10cSrcweir 530cdf0e10cSrcweir void BaseNode::activate_st() 531cdf0e10cSrcweir { 532cdf0e10cSrcweir scheduleDeactivationEvent(); 533cdf0e10cSrcweir } 534cdf0e10cSrcweir 535cdf0e10cSrcweir void BaseNode::scheduleDeactivationEvent( EventSharedPtr const& pEvent ) 536cdf0e10cSrcweir { 537cdf0e10cSrcweir if (mpCurrentEvent) { 538cdf0e10cSrcweir mpCurrentEvent->dispose(); 539cdf0e10cSrcweir mpCurrentEvent.reset(); 540cdf0e10cSrcweir } 541cdf0e10cSrcweir if (pEvent) { 542cdf0e10cSrcweir if (maContext.mrEventQueue.addEvent( pEvent )) 543cdf0e10cSrcweir mpCurrentEvent = pEvent; 544cdf0e10cSrcweir } 545cdf0e10cSrcweir else { 546cdf0e10cSrcweir // This method need not take the 547cdf0e10cSrcweir // NodeContext::mnStartDelay value into account, 548cdf0e10cSrcweir // because the deactivation event is only scheduled 549cdf0e10cSrcweir // when the effect is started: the timeout is then 550cdf0e10cSrcweir // already respected. 551cdf0e10cSrcweir 552cdf0e10cSrcweir // xxx todo: 553cdf0e10cSrcweir // think about set node, anim base node! 554cdf0e10cSrcweir // if anim base node has no activity, this is called to schedule deactivatiion, 555cdf0e10cSrcweir // but what if it does not schedule anything? 556cdf0e10cSrcweir 557cdf0e10cSrcweir // TODO(F2): Handle end time attribute, too 558cdf0e10cSrcweir mpCurrentEvent = generateEvent( 559cdf0e10cSrcweir mxAnimationNode->getDuration(), 560cdf0e10cSrcweir boost::bind( &AnimationNode::deactivate, mpSelf ), 561cdf0e10cSrcweir maContext, 0.0 ); 562cdf0e10cSrcweir } 563cdf0e10cSrcweir } 564cdf0e10cSrcweir 565cdf0e10cSrcweir void BaseNode::deactivate() 566cdf0e10cSrcweir { 567cdf0e10cSrcweir if (inStateOrTransition( ENDED | FROZEN ) || !checkValidNode()) 568cdf0e10cSrcweir return; 569cdf0e10cSrcweir 570cdf0e10cSrcweir if (isTransition( meCurrState, FROZEN, false /* no OSL_ASSERT */ )) { 571cdf0e10cSrcweir // do transition to FROZEN: 572cdf0e10cSrcweir StateTransition st(this); 573cdf0e10cSrcweir if (st.enter( FROZEN, StateTransition::FORCE )) { 574cdf0e10cSrcweir 575cdf0e10cSrcweir deactivate_st( FROZEN ); 576cdf0e10cSrcweir st.commit(); 577cdf0e10cSrcweir 578cdf0e10cSrcweir notifyEndListeners(); 579cdf0e10cSrcweir 580cdf0e10cSrcweir // discharge a loaded event, before going on: 581cdf0e10cSrcweir if (mpCurrentEvent) { 582cdf0e10cSrcweir mpCurrentEvent->dispose(); 583cdf0e10cSrcweir mpCurrentEvent.reset(); 584cdf0e10cSrcweir } 585cdf0e10cSrcweir } 586cdf0e10cSrcweir } 587cdf0e10cSrcweir else { 588cdf0e10cSrcweir // use end instead: 589cdf0e10cSrcweir end(); 590cdf0e10cSrcweir } 591cdf0e10cSrcweir // state has changed either to FROZEN or ENDED 592cdf0e10cSrcweir } 593cdf0e10cSrcweir 594cdf0e10cSrcweir void BaseNode::deactivate_st( NodeState ) 595cdf0e10cSrcweir { 596cdf0e10cSrcweir } 597cdf0e10cSrcweir 598cdf0e10cSrcweir void BaseNode::end() 599cdf0e10cSrcweir { 600cdf0e10cSrcweir bool const bIsFrozenOrInTransitionToFrozen = inStateOrTransition( FROZEN ); 601cdf0e10cSrcweir if (inStateOrTransition( ENDED ) || !checkValidNode()) 602cdf0e10cSrcweir return; 603cdf0e10cSrcweir 604cdf0e10cSrcweir // END must always be reachable. If not, that's an error in the 605cdf0e10cSrcweir // transition tables 606cdf0e10cSrcweir OSL_ENSURE( isTransition( meCurrState, ENDED ), 607cdf0e10cSrcweir "end state not reachable in transition table" ); 608cdf0e10cSrcweir 609cdf0e10cSrcweir StateTransition st(this); 610cdf0e10cSrcweir if (st.enter( ENDED, StateTransition::FORCE )) { 611cdf0e10cSrcweir 612cdf0e10cSrcweir deactivate_st( ENDED ); 613cdf0e10cSrcweir st.commit(); // changing state 614cdf0e10cSrcweir 615cdf0e10cSrcweir // if is FROZEN or is to be FROZEN, then 616cdf0e10cSrcweir // will/already notified deactivating listeners 617cdf0e10cSrcweir if (!bIsFrozenOrInTransitionToFrozen) 618cdf0e10cSrcweir notifyEndListeners(); 619cdf0e10cSrcweir 620cdf0e10cSrcweir // discharge a loaded event, before going on: 621cdf0e10cSrcweir if (mpCurrentEvent) { 622cdf0e10cSrcweir mpCurrentEvent->dispose(); 623cdf0e10cSrcweir mpCurrentEvent.reset(); 624cdf0e10cSrcweir } 625cdf0e10cSrcweir } 626cdf0e10cSrcweir } 627cdf0e10cSrcweir 628cdf0e10cSrcweir void BaseNode::notifyDeactivating( const AnimationNodeSharedPtr& rNotifier ) 629cdf0e10cSrcweir { 630cdf0e10cSrcweir (void) rNotifier; // avoid warning 631cdf0e10cSrcweir OSL_ASSERT( rNotifier->getState() == FROZEN || 632cdf0e10cSrcweir rNotifier->getState() == ENDED ); 633cdf0e10cSrcweir // TODO(F1): for end sync functionality, this might indeed be used some day 634cdf0e10cSrcweir } 635cdf0e10cSrcweir 636cdf0e10cSrcweir void BaseNode::notifyEndListeners() const 637cdf0e10cSrcweir { 638cdf0e10cSrcweir // notify all listeners 639cdf0e10cSrcweir std::for_each( maDeactivatingListeners.begin(), 640cdf0e10cSrcweir maDeactivatingListeners.end(), 641cdf0e10cSrcweir boost::bind( &AnimationNode::notifyDeactivating, _1, 642cdf0e10cSrcweir boost::cref(mpSelf) ) ); 643cdf0e10cSrcweir 644cdf0e10cSrcweir // notify state change 645cdf0e10cSrcweir maContext.mrEventMultiplexer.notifyAnimationEnd( mpSelf ); 646cdf0e10cSrcweir 647cdf0e10cSrcweir // notify main sequence end (iff we're the main 648cdf0e10cSrcweir // sequence root node). This is because the main 649cdf0e10cSrcweir // sequence determines the active duration of the 650cdf0e10cSrcweir // slide. All other sequences are secondary, in that 651cdf0e10cSrcweir // they don't prevent a slide change from happening, 652cdf0e10cSrcweir // even if they have not been completed. In other 653cdf0e10cSrcweir // words, all sequences except the main sequence are 654cdf0e10cSrcweir // optional for the slide lifetime. 655cdf0e10cSrcweir if (isMainSequenceRootNode()) 656cdf0e10cSrcweir maContext.mrEventMultiplexer.notifySlideAnimationsEnd(); 657cdf0e10cSrcweir } 658cdf0e10cSrcweir 659cdf0e10cSrcweir AnimationNode::NodeState BaseNode::getState() const 660cdf0e10cSrcweir { 661cdf0e10cSrcweir return meCurrState; 662cdf0e10cSrcweir } 663cdf0e10cSrcweir 664cdf0e10cSrcweir bool BaseNode::registerDeactivatingListener( 665cdf0e10cSrcweir const AnimationNodeSharedPtr& rNotifee ) 666cdf0e10cSrcweir { 667cdf0e10cSrcweir if (! checkValidNode()) 668cdf0e10cSrcweir return false; 669cdf0e10cSrcweir 670cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( 671cdf0e10cSrcweir rNotifee, 672cdf0e10cSrcweir "BaseNode::registerDeactivatingListener(): invalid notifee" ); 673cdf0e10cSrcweir maDeactivatingListeners.push_back( rNotifee ); 674cdf0e10cSrcweir 675cdf0e10cSrcweir return true; 676cdf0e10cSrcweir } 677cdf0e10cSrcweir 678cdf0e10cSrcweir void BaseNode::setSelf( const BaseNodeSharedPtr& rSelf ) 679cdf0e10cSrcweir { 680cdf0e10cSrcweir ENSURE_OR_THROW( rSelf.get() == this, 681cdf0e10cSrcweir "BaseNode::setSelf(): got ptr to different object" ); 682cdf0e10cSrcweir ENSURE_OR_THROW( !mpSelf, 683cdf0e10cSrcweir "BaseNode::setSelf(): called multiple times" ); 684cdf0e10cSrcweir 685cdf0e10cSrcweir mpSelf = rSelf; 686cdf0e10cSrcweir } 687cdf0e10cSrcweir 688cdf0e10cSrcweir // Debug 689cdf0e10cSrcweir //========================================================================= 690cdf0e10cSrcweir 691cdf0e10cSrcweir #if defined(VERBOSE) && defined(DBG_UTIL) 692cdf0e10cSrcweir void BaseNode::showState() const 693cdf0e10cSrcweir { 694cdf0e10cSrcweir const AnimationNode::NodeState eNodeState( getState() ); 695cdf0e10cSrcweir 696cdf0e10cSrcweir if( eNodeState == AnimationNode::INVALID ) 697cdf0e10cSrcweir VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled," 698cdf0e10cSrcweir "fillcolor=\"0.5,0.2,0.5\"]", 699cdf0e10cSrcweir (const char*)this+debugGetCurrentOffset(), 700cdf0e10cSrcweir getDescription() ); 701cdf0e10cSrcweir else 702cdf0e10cSrcweir VERBOSE_TRACE( "Node state: n0x%X [label=\"%s\",style=filled," 703cdf0e10cSrcweir "fillcolor=\"%f,1.0,1.0\"]", 704cdf0e10cSrcweir (const char*)this+debugGetCurrentOffset(), 705cdf0e10cSrcweir getDescription(), 706cdf0e10cSrcweir log(double(getState()))/4.0 ); 707cdf0e10cSrcweir 708cdf0e10cSrcweir // determine additional node information 709cdf0e10cSrcweir uno::Reference<animations::XAnimate> const xAnimate( mxAnimationNode, 710cdf0e10cSrcweir uno::UNO_QUERY ); 711cdf0e10cSrcweir if( xAnimate.is() ) 712cdf0e10cSrcweir { 713cdf0e10cSrcweir uno::Reference< drawing::XShape > xTargetShape( xAnimate->getTarget(), 714cdf0e10cSrcweir uno::UNO_QUERY ); 715cdf0e10cSrcweir 716cdf0e10cSrcweir if( !xTargetShape.is() ) 717cdf0e10cSrcweir { 718cdf0e10cSrcweir ::com::sun::star::presentation::ParagraphTarget aTarget; 719cdf0e10cSrcweir 720cdf0e10cSrcweir // no shape provided. Maybe a ParagraphTarget? 721cdf0e10cSrcweir if( (xAnimate->getTarget() >>= aTarget) ) 722cdf0e10cSrcweir xTargetShape = aTarget.Shape; 723cdf0e10cSrcweir } 724cdf0e10cSrcweir 725cdf0e10cSrcweir if( xTargetShape.is() ) 726cdf0e10cSrcweir { 727cdf0e10cSrcweir uno::Reference< beans::XPropertySet > xPropSet( xTargetShape, 728cdf0e10cSrcweir uno::UNO_QUERY ); 729cdf0e10cSrcweir 730cdf0e10cSrcweir // read shape name 731cdf0e10cSrcweir ::rtl::OUString aName; 732cdf0e10cSrcweir if( (xPropSet->getPropertyValue( 733cdf0e10cSrcweir ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Name") ) ) 734cdf0e10cSrcweir >>= aName) ) 735cdf0e10cSrcweir { 736cdf0e10cSrcweir const ::rtl::OString& rAsciiName( 737cdf0e10cSrcweir ::rtl::OUStringToOString( aName, 738cdf0e10cSrcweir RTL_TEXTENCODING_ASCII_US ) ); 739cdf0e10cSrcweir 740cdf0e10cSrcweir VERBOSE_TRACE( "Node info: n0x%X, name \"%s\"", 741cdf0e10cSrcweir (const char*)this+debugGetCurrentOffset(), 742cdf0e10cSrcweir rAsciiName.getStr() ); 743cdf0e10cSrcweir } 744cdf0e10cSrcweir } 745cdf0e10cSrcweir } 746cdf0e10cSrcweir } 747cdf0e10cSrcweir 748cdf0e10cSrcweir const char* BaseNode::getDescription() const 749cdf0e10cSrcweir { 750cdf0e10cSrcweir return "BaseNode"; 751cdf0e10cSrcweir } 752cdf0e10cSrcweir 753cdf0e10cSrcweir void BaseNode::showTreeFromWithin() const 754cdf0e10cSrcweir { 755cdf0e10cSrcweir // find root node 756cdf0e10cSrcweir BaseNodeSharedPtr pCurrNode( mpSelf ); 757cdf0e10cSrcweir while( pCurrNode->mpParent ) pCurrNode = pCurrNode->mpParent; 758cdf0e10cSrcweir 759cdf0e10cSrcweir pCurrNode->showState(); 760cdf0e10cSrcweir } 761cdf0e10cSrcweir #endif 762cdf0e10cSrcweir 763cdf0e10cSrcweir } // namespace internal 764cdf0e10cSrcweir } // namespace slideshow 765cdf0e10cSrcweir 766