blob: d3a3103d67ce8e9449467f457e4455795c45384c [file] [log] [blame]
/**************************************************************
*
* 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 <canvas/debug.hxx>
#include <tools/diagnose_ex.h>
#include <canvas/verbosetrace.hxx>
#include <discreteactivitybase.hxx>
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<len; ++i )
{
if( maDiscreteTimes[i] < 0.0 ||
maDiscreteTimes[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();
}
}
}