/************************************************************** * * 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_slideshow.hxx" // must be first #include #include #include #include namespace slideshow { namespace internal { DiscreteActivityBase::DiscreteActivityBase( const ActivityParameters& rParms ) : ActivityBase( rParms ), mpWakeupEvent( rParms.mpWakeupEvent ), maDiscreteTimes( rParms.maDiscreteTimes ), mnSimpleDuration( rParms.mnMinDuration ), mnCurrPerformCalls( 0 ) { ENSURE_OR_THROW( mpWakeupEvent, "DiscreteActivityBase::DiscreteActivityBase(): Invalid wakeup event" ); ENSURE_OR_THROW( !maDiscreteTimes.empty(), "DiscreteActivityBase::DiscreteActivityBase(): time vector is empty, why do you create me?" ); #ifdef DBG_UTIL // check parameters: rDiscreteTimes must be sorted in // ascending order, and contain values only from the range // [0,1] for( ::std::size_t i=1, len=maDiscreteTimes.size(); i 1.0 || maDiscreteTimes[i-1] < 0.0 || maDiscreteTimes[i-1] > 1.0 ) { ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time values not within [0,1] range!" ); } if( maDiscreteTimes[i-1] > maDiscreteTimes[i] ) ENSURE_OR_THROW( false, "DiscreteActivityBase::DiscreteActivityBase(): time vector is not sorted in ascending order!" ); } // TODO(E2): check this also in production code? #endif } void DiscreteActivityBase::startAnimation() { // start timer on wakeup event mpWakeupEvent->start(); } sal_uInt32 DiscreteActivityBase::calcFrameIndex( sal_uInt32 nCurrCalls, ::std::size_t nVectorSize ) const { if( isAutoReverse() ) { // every full repeat run consists of one // forward and one backward traversal. sal_uInt32 nFrameIndex( nCurrCalls % (2*nVectorSize) ); // nFrameIndex values >= nVectorSize belong to // the backward traversal if( nFrameIndex >= nVectorSize ) nFrameIndex = 2*nVectorSize - nFrameIndex; // invert sweep return nFrameIndex; } else { return nCurrCalls % nVectorSize ; } } sal_uInt32 DiscreteActivityBase::calcRepeatCount( sal_uInt32 nCurrCalls, ::std::size_t nVectorSize ) const { if( isAutoReverse() ) return nCurrCalls / (2*nVectorSize); // we've got 2 cycles per repeat else return nCurrCalls / nVectorSize; } bool DiscreteActivityBase::perform() { // call base class, for start() calls and end handling if( !ActivityBase::perform() ) return false; // done, we're ended const ::std::size_t nVectorSize( maDiscreteTimes.size() ); // actually perform something // ========================== // TODO(Q3): Refactor this mess // call derived class with current frame index (modulo // vector size, to cope with repeats) perform( calcFrameIndex( mnCurrPerformCalls, nVectorSize ), calcRepeatCount( mnCurrPerformCalls, nVectorSize ) ); // calc next index ++mnCurrPerformCalls; // calc currently reached repeat count double nCurrRepeat( double(mnCurrPerformCalls) / nVectorSize ); // if auto-reverse is specified, halve the // effective repeat count, since we pass every // repeat run twice: once forward, once backward. if( isAutoReverse() ) nCurrRepeat /= 2.0; // schedule next frame, if either repeat is indefinite // (repeat forever), or we've not yet reached the requested // repeat count if( !isRepeatCountValid() || nCurrRepeat < getRepeatCount() ) { // add wake-up event to queue (modulo // vector size, to cope with repeats). // repeat is handled locally, only apply acceleration/deceleration. // Scale time vector with simple duration, offset with full repeat // times. // // Somewhat condensed, the argument for setNextTimeout below could // be written as // // mnSimpleDuration*(nFullRepeats + calcAcceleratedTime( currentRepeatTime )), // // with currentRepeatTime = maDiscreteTimes[ currentRepeatIndex ] // // Note that calcAcceleratedTime() is only applied to the current repeat's value, // not to the total resulting time. This is in accordance with the SMIL spec. // mpWakeupEvent->setNextTimeout( mnSimpleDuration*( calcRepeatCount( mnCurrPerformCalls, nVectorSize ) + calcAcceleratedTime( maDiscreteTimes[ calcFrameIndex( mnCurrPerformCalls, nVectorSize ) ] ) ) ); getEventQueue().addEvent( mpWakeupEvent ); } else { // release event reference (relation to wakeup event // is circular!) mpWakeupEvent.reset(); // done with this activity endActivity(); } return false; // remove from queue, will be added back by the wakeup event. } void DiscreteActivityBase::dispose() { // dispose event if( mpWakeupEvent ) mpWakeupEvent->dispose(); // release references mpWakeupEvent.reset(); ActivityBase::dispose(); } } }