1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_slideshow.hxx" 26 27 // must be first 28 #include <canvas/debug.hxx> 29 #include <tools/diagnose_ex.h> 30 #include <canvas/verbosetrace.hxx> 31 #include <canvas/canvastools.hxx> 32 33 #include <activitybase.hxx> 34 35 36 namespace slideshow 37 { 38 namespace internal 39 { 40 // TODO(P1): Elide some virtual function calls, by templifying this 41 // static hierarchy 42 ActivityBase(const ActivityParameters & rParms)43 ActivityBase::ActivityBase( const ActivityParameters& rParms ) : 44 mpEndEvent( rParms.mrEndEvent ), 45 mrEventQueue( rParms.mrEventQueue ), 46 mpShape(), 47 mpAttributeLayer(), 48 maRepeats( rParms.mrRepeats ), 49 mnAccelerationFraction( rParms.mnAccelerationFraction ), 50 mnDecelerationFraction( rParms.mnDecelerationFraction ), 51 mbAutoReverse( rParms.mbAutoReverse ), 52 mbFirstPerformCall( true ), 53 mbIsActive( true ) {} 54 dispose()55 void ActivityBase::dispose() 56 { 57 // deactivate 58 mbIsActive = false; 59 60 // dispose event 61 if( mpEndEvent ) 62 mpEndEvent->dispose(); 63 64 // release references 65 mpEndEvent.reset(); 66 mpShape.reset(); 67 mpAttributeLayer.reset(); 68 } 69 calcTimeLag() const70 double ActivityBase::calcTimeLag() const 71 { 72 // TODO(Q1): implement different init process! 73 if (isActive() && mbFirstPerformCall) 74 { 75 mbFirstPerformCall = false; 76 77 // notify derived classes that we're 78 // starting now 79 const_cast<ActivityBase *>(this)->startAnimation(); 80 } 81 return 0.0; 82 } 83 perform()84 bool ActivityBase::perform() 85 { 86 // still active? 87 if( !isActive() ) 88 return false; // no, early exit. 89 90 OSL_ASSERT( ! mbFirstPerformCall ); 91 92 return true; 93 } 94 isActive() const95 bool ActivityBase::isActive() const 96 { 97 return mbIsActive; 98 } 99 setTargets(const AnimatableShapeSharedPtr & rShape,const ShapeAttributeLayerSharedPtr & rAttrLayer)100 void ActivityBase::setTargets( const AnimatableShapeSharedPtr& rShape, 101 const ShapeAttributeLayerSharedPtr& rAttrLayer ) 102 { 103 ENSURE_OR_THROW( rShape, 104 "ActivityBase::setTargets(): Invalid shape" ); 105 ENSURE_OR_THROW( rAttrLayer, 106 "ActivityBase::setTargets(): Invalid attribute layer" ); 107 108 mpShape = rShape; 109 mpAttributeLayer = rAttrLayer; 110 } 111 endActivity()112 void ActivityBase::endActivity() 113 { 114 // this is a regular activity end 115 mbIsActive = false; 116 117 // Activity is ending, queue event, then 118 if( mpEndEvent ) 119 mrEventQueue.addEvent( mpEndEvent ); 120 121 // release references 122 mpEndEvent.reset(); 123 } 124 dequeued()125 void ActivityBase::dequeued() 126 { 127 // xxx todo: 128 // // ignored here, if we're still active. Discrete 129 // // activities are dequeued after every perform() call, 130 // // thus, the call is only significant when isActive() == 131 // // false. 132 if( !isActive() ) 133 endAnimation(); 134 } 135 end()136 void ActivityBase::end() 137 { 138 if (!isActive() || isDisposed()) 139 return; 140 // assure animation is started: 141 if (mbFirstPerformCall) { 142 mbFirstPerformCall = false; 143 // notify derived classes that we're starting now 144 this->startAnimation(); 145 } 146 147 performEnd(); // calling private virtual 148 endAnimation(); 149 endActivity(); 150 } 151 calcAcceleratedTime(double nT) const152 double ActivityBase::calcAcceleratedTime( double nT ) const 153 { 154 // Handle acceleration/deceleration 155 // ================================ 156 157 // clamp nT to permissible [0,1] range 158 nT = ::basegfx::clamp( nT, 0.0, 1.0 ); 159 160 // take acceleration/deceleration into account. if the sum 161 // of mnAccelerationFraction and mnDecelerationFraction 162 // exceeds 1.0, ignore both (that's according to SMIL spec) 163 if( (mnAccelerationFraction > 0.0 || 164 mnDecelerationFraction > 0.0) && 165 mnAccelerationFraction + mnDecelerationFraction <= 1.0 ) 166 { 167 /* 168 // calc accelerated/decelerated time. 169 // 170 // We have three intervals: 171 // 1 [0,a] 172 // 2 [a,d] 173 // 3 [d,1] (with a and d being acceleration/deceleration 174 // fraction, resp.) 175 // 176 // The change rate during interval 1 is constantly 177 // increasing, reaching 1 at a. It then stays at 1, 178 // starting a linear decrease at d, ending with 0 at 179 // time 1. The integral of this function is the 180 // required new time nT'. 181 // 182 // As we arbitrarily assumed 1 as the upper value of 183 // the change rate, the integral must be normalized to 184 // reach nT'=1 at the end of the interval. This 185 // normalization constant is: 186 // 187 // c = 1 - 0.5a - 0.5d 188 // 189 // The integral itself then amounts to: 190 // 191 // 0.5 nT^2 / a + (nT-a) + (nT - 0.5 nT^2 / d) 192 // 193 // (where each of the three summands correspond to the 194 // three intervals above, and are applied only if nT 195 // has reached the corresponding interval) 196 // 197 // The graph of the change rate is a trapezoid: 198 // 199 // | 200 // 1| /--------------\ 201 // | / \ 202 // | / \ 203 // | / \ 204 // ----------------------------- 205 // 0 a d 1 206 // 207 //*/ 208 const double nC( 1.0 - 0.5*mnAccelerationFraction - 0.5*mnDecelerationFraction ); 209 210 // this variable accumulates the new time value 211 double nTPrime(0.0); 212 213 if( nT < mnAccelerationFraction ) 214 { 215 nTPrime += 0.5*nT*nT/mnAccelerationFraction; // partial first interval 216 } 217 else 218 { 219 nTPrime += 0.5*mnAccelerationFraction; // full first interval 220 221 if( nT <= 1.0-mnDecelerationFraction ) 222 { 223 nTPrime += nT-mnAccelerationFraction; // partial second interval 224 } 225 else 226 { 227 nTPrime += 1.0 - mnAccelerationFraction - mnDecelerationFraction; // full second interval 228 229 const double nTRelative( nT - 1.0 + mnDecelerationFraction ); 230 231 nTPrime += nTRelative - 0.5*nTRelative*nTRelative / mnDecelerationFraction; 232 } 233 } 234 235 // normalize, and assign to work variable 236 nT = nTPrime / nC; 237 } 238 239 return nT; 240 } 241 } 242 } 243