1*b1cdbd2cSJim Jagielski /************************************************************** 2*b1cdbd2cSJim Jagielski * 3*b1cdbd2cSJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski * or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski * distributed with this work for additional information 6*b1cdbd2cSJim Jagielski * regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski * to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski * "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski * with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski * 11*b1cdbd2cSJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski * 13*b1cdbd2cSJim Jagielski * Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski * software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski * KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski * specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski * under the License. 19*b1cdbd2cSJim Jagielski * 20*b1cdbd2cSJim Jagielski *************************************************************/ 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski 23*b1cdbd2cSJim Jagielski 24*b1cdbd2cSJim Jagielski // MARKER(update_precomp.py): autogen include statement, do not remove 25*b1cdbd2cSJim Jagielski #include "precompiled_slideshow.hxx" 26*b1cdbd2cSJim Jagielski 27*b1cdbd2cSJim Jagielski // must be first 28*b1cdbd2cSJim Jagielski #include <canvas/debug.hxx> 29*b1cdbd2cSJim Jagielski #include <tools/diagnose_ex.h> 30*b1cdbd2cSJim Jagielski #include <canvas/verbosetrace.hxx> 31*b1cdbd2cSJim Jagielski 32*b1cdbd2cSJim Jagielski #include <discreteactivitybase.hxx> 33*b1cdbd2cSJim Jagielski 34*b1cdbd2cSJim Jagielski 35*b1cdbd2cSJim Jagielski namespace slideshow 36*b1cdbd2cSJim Jagielski { 37*b1cdbd2cSJim Jagielski namespace internal 38*b1cdbd2cSJim Jagielski { DiscreteActivityBase(const ActivityParameters & rParms)39*b1cdbd2cSJim Jagielski DiscreteActivityBase::DiscreteActivityBase( const ActivityParameters& rParms ) : 40*b1cdbd2cSJim Jagielski ActivityBase( rParms ), 41*b1cdbd2cSJim Jagielski mpWakeupEvent( rParms.mpWakeupEvent ), 42*b1cdbd2cSJim Jagielski maDiscreteTimes( rParms.maDiscreteTimes ), 43*b1cdbd2cSJim Jagielski mnSimpleDuration( rParms.mnMinDuration ), 44*b1cdbd2cSJim Jagielski mnCurrPerformCalls( 0 ) 45*b1cdbd2cSJim Jagielski { 46*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( mpWakeupEvent, 47*b1cdbd2cSJim Jagielski "DiscreteActivityBase::DiscreteActivityBase(): Invalid wakeup event" ); 48*b1cdbd2cSJim Jagielski 49*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( !maDiscreteTimes.empty(), 50*b1cdbd2cSJim Jagielski "DiscreteActivityBase::DiscreteActivityBase(): time vector is empty, why do you create me?" ); 51*b1cdbd2cSJim Jagielski 52*b1cdbd2cSJim Jagielski #ifdef DBG_UTIL 53*b1cdbd2cSJim Jagielski // check parameters: rDiscreteTimes must be sorted in 54*b1cdbd2cSJim Jagielski // ascending order, and contain values only from the range 55*b1cdbd2cSJim Jagielski // [0,1] 56*b1cdbd2cSJim Jagielski for( ::std::size_t i=1, len=maDiscreteTimes.size(); i<len; ++i ) 57*b1cdbd2cSJim Jagielski { 58*b1cdbd2cSJim Jagielski if( maDiscreteTimes[i] < 0.0 || 59*b1cdbd2cSJim Jagielski maDiscreteTimes[i] > 1.0 || 60*b1cdbd2cSJim Jagielski maDiscreteTimes[i-1] < 0.0 || 61*b1cdbd2cSJim Jagielski maDiscreteTimes[i-1] > 1.0 ) 62*b1cdbd2cSJim Jagielski { 63*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time values not within [0,1] range!" ); 64*b1cdbd2cSJim Jagielski } 65*b1cdbd2cSJim Jagielski 66*b1cdbd2cSJim Jagielski if( maDiscreteTimes[i-1] > maDiscreteTimes[i] ) 67*b1cdbd2cSJim Jagielski ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time vector is not sorted in ascending order!" ); 68*b1cdbd2cSJim Jagielski } 69*b1cdbd2cSJim Jagielski 70*b1cdbd2cSJim Jagielski // TODO(E2): check this also in production code? 71*b1cdbd2cSJim Jagielski #endif 72*b1cdbd2cSJim Jagielski } 73*b1cdbd2cSJim Jagielski startAnimation()74*b1cdbd2cSJim Jagielski void DiscreteActivityBase::startAnimation() 75*b1cdbd2cSJim Jagielski { 76*b1cdbd2cSJim Jagielski // start timer on wakeup event 77*b1cdbd2cSJim Jagielski mpWakeupEvent->start(); 78*b1cdbd2cSJim Jagielski } 79*b1cdbd2cSJim Jagielski calcFrameIndex(sal_uInt32 nCurrCalls,::std::size_t nVectorSize) const80*b1cdbd2cSJim Jagielski sal_uInt32 DiscreteActivityBase::calcFrameIndex( sal_uInt32 nCurrCalls, 81*b1cdbd2cSJim Jagielski ::std::size_t nVectorSize ) const 82*b1cdbd2cSJim Jagielski { 83*b1cdbd2cSJim Jagielski if( isAutoReverse() ) 84*b1cdbd2cSJim Jagielski { 85*b1cdbd2cSJim Jagielski // every full repeat run consists of one 86*b1cdbd2cSJim Jagielski // forward and one backward traversal. 87*b1cdbd2cSJim Jagielski sal_uInt32 nFrameIndex( nCurrCalls % (2*nVectorSize) ); 88*b1cdbd2cSJim Jagielski 89*b1cdbd2cSJim Jagielski // nFrameIndex values >= nVectorSize belong to 90*b1cdbd2cSJim Jagielski // the backward traversal 91*b1cdbd2cSJim Jagielski if( nFrameIndex >= nVectorSize ) 92*b1cdbd2cSJim Jagielski nFrameIndex = 2*nVectorSize - nFrameIndex; // invert sweep 93*b1cdbd2cSJim Jagielski 94*b1cdbd2cSJim Jagielski return nFrameIndex; 95*b1cdbd2cSJim Jagielski } 96*b1cdbd2cSJim Jagielski else 97*b1cdbd2cSJim Jagielski { 98*b1cdbd2cSJim Jagielski return nCurrCalls % nVectorSize ; 99*b1cdbd2cSJim Jagielski } 100*b1cdbd2cSJim Jagielski } 101*b1cdbd2cSJim Jagielski calcRepeatCount(sal_uInt32 nCurrCalls,::std::size_t nVectorSize) const102*b1cdbd2cSJim Jagielski sal_uInt32 DiscreteActivityBase::calcRepeatCount( sal_uInt32 nCurrCalls, 103*b1cdbd2cSJim Jagielski ::std::size_t nVectorSize ) const 104*b1cdbd2cSJim Jagielski { 105*b1cdbd2cSJim Jagielski if( isAutoReverse() ) 106*b1cdbd2cSJim Jagielski return nCurrCalls / (2*nVectorSize); // we've got 2 cycles per repeat 107*b1cdbd2cSJim Jagielski else 108*b1cdbd2cSJim Jagielski return nCurrCalls / nVectorSize; 109*b1cdbd2cSJim Jagielski } 110*b1cdbd2cSJim Jagielski perform()111*b1cdbd2cSJim Jagielski bool DiscreteActivityBase::perform() 112*b1cdbd2cSJim Jagielski { 113*b1cdbd2cSJim Jagielski // call base class, for start() calls and end handling 114*b1cdbd2cSJim Jagielski if( !ActivityBase::perform() ) 115*b1cdbd2cSJim Jagielski return false; // done, we're ended 116*b1cdbd2cSJim Jagielski 117*b1cdbd2cSJim Jagielski const ::std::size_t nVectorSize( maDiscreteTimes.size() ); 118*b1cdbd2cSJim Jagielski 119*b1cdbd2cSJim Jagielski // actually perform something 120*b1cdbd2cSJim Jagielski // ========================== 121*b1cdbd2cSJim Jagielski 122*b1cdbd2cSJim Jagielski // TODO(Q3): Refactor this mess 123*b1cdbd2cSJim Jagielski 124*b1cdbd2cSJim Jagielski // call derived class with current frame index (modulo 125*b1cdbd2cSJim Jagielski // vector size, to cope with repeats) 126*b1cdbd2cSJim Jagielski perform( calcFrameIndex( mnCurrPerformCalls, nVectorSize ), 127*b1cdbd2cSJim Jagielski calcRepeatCount( mnCurrPerformCalls, nVectorSize ) ); 128*b1cdbd2cSJim Jagielski 129*b1cdbd2cSJim Jagielski // calc next index 130*b1cdbd2cSJim Jagielski ++mnCurrPerformCalls; 131*b1cdbd2cSJim Jagielski 132*b1cdbd2cSJim Jagielski // calc currently reached repeat count 133*b1cdbd2cSJim Jagielski double nCurrRepeat( double(mnCurrPerformCalls) / nVectorSize ); 134*b1cdbd2cSJim Jagielski 135*b1cdbd2cSJim Jagielski // if auto-reverse is specified, halve the 136*b1cdbd2cSJim Jagielski // effective repeat count, since we pass every 137*b1cdbd2cSJim Jagielski // repeat run twice: once forward, once backward. 138*b1cdbd2cSJim Jagielski if( isAutoReverse() ) 139*b1cdbd2cSJim Jagielski nCurrRepeat /= 2.0; 140*b1cdbd2cSJim Jagielski 141*b1cdbd2cSJim Jagielski // schedule next frame, if either repeat is indefinite 142*b1cdbd2cSJim Jagielski // (repeat forever), or we've not yet reached the requested 143*b1cdbd2cSJim Jagielski // repeat count 144*b1cdbd2cSJim Jagielski if( !isRepeatCountValid() || 145*b1cdbd2cSJim Jagielski nCurrRepeat < getRepeatCount() ) 146*b1cdbd2cSJim Jagielski { 147*b1cdbd2cSJim Jagielski // add wake-up event to queue (modulo 148*b1cdbd2cSJim Jagielski // vector size, to cope with repeats). 149*b1cdbd2cSJim Jagielski 150*b1cdbd2cSJim Jagielski // repeat is handled locally, only apply acceleration/deceleration. 151*b1cdbd2cSJim Jagielski // Scale time vector with simple duration, offset with full repeat 152*b1cdbd2cSJim Jagielski // times. 153*b1cdbd2cSJim Jagielski // 154*b1cdbd2cSJim Jagielski // Somewhat condensed, the argument for setNextTimeout below could 155*b1cdbd2cSJim Jagielski // be written as 156*b1cdbd2cSJim Jagielski // 157*b1cdbd2cSJim Jagielski // mnSimpleDuration*(nFullRepeats + calcAcceleratedTime( currentRepeatTime )), 158*b1cdbd2cSJim Jagielski // 159*b1cdbd2cSJim Jagielski // with currentRepeatTime = maDiscreteTimes[ currentRepeatIndex ] 160*b1cdbd2cSJim Jagielski // 161*b1cdbd2cSJim Jagielski // Note that calcAcceleratedTime() is only applied to the current repeat's value, 162*b1cdbd2cSJim Jagielski // not to the total resulting time. This is in accordance with the SMIL spec. 163*b1cdbd2cSJim Jagielski // 164*b1cdbd2cSJim Jagielski mpWakeupEvent->setNextTimeout( 165*b1cdbd2cSJim Jagielski mnSimpleDuration*( 166*b1cdbd2cSJim Jagielski calcRepeatCount( 167*b1cdbd2cSJim Jagielski mnCurrPerformCalls, 168*b1cdbd2cSJim Jagielski nVectorSize ) + 169*b1cdbd2cSJim Jagielski calcAcceleratedTime( 170*b1cdbd2cSJim Jagielski maDiscreteTimes[ 171*b1cdbd2cSJim Jagielski calcFrameIndex( 172*b1cdbd2cSJim Jagielski mnCurrPerformCalls, 173*b1cdbd2cSJim Jagielski nVectorSize ) ] ) ) ); 174*b1cdbd2cSJim Jagielski 175*b1cdbd2cSJim Jagielski getEventQueue().addEvent( mpWakeupEvent ); 176*b1cdbd2cSJim Jagielski } 177*b1cdbd2cSJim Jagielski else 178*b1cdbd2cSJim Jagielski { 179*b1cdbd2cSJim Jagielski // release event reference (relation to wakeup event 180*b1cdbd2cSJim Jagielski // is circular!) 181*b1cdbd2cSJim Jagielski mpWakeupEvent.reset(); 182*b1cdbd2cSJim Jagielski 183*b1cdbd2cSJim Jagielski // done with this activity 184*b1cdbd2cSJim Jagielski endActivity(); 185*b1cdbd2cSJim Jagielski } 186*b1cdbd2cSJim Jagielski 187*b1cdbd2cSJim Jagielski return false; // remove from queue, will be added back by the wakeup event. 188*b1cdbd2cSJim Jagielski } 189*b1cdbd2cSJim Jagielski dispose()190*b1cdbd2cSJim Jagielski void DiscreteActivityBase::dispose() 191*b1cdbd2cSJim Jagielski { 192*b1cdbd2cSJim Jagielski // dispose event 193*b1cdbd2cSJim Jagielski if( mpWakeupEvent ) 194*b1cdbd2cSJim Jagielski mpWakeupEvent->dispose(); 195*b1cdbd2cSJim Jagielski 196*b1cdbd2cSJim Jagielski // release references 197*b1cdbd2cSJim Jagielski mpWakeupEvent.reset(); 198*b1cdbd2cSJim Jagielski 199*b1cdbd2cSJim Jagielski ActivityBase::dispose(); 200*b1cdbd2cSJim Jagielski } 201*b1cdbd2cSJim Jagielski } 202*b1cdbd2cSJim Jagielski } 203