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