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 #include <canvas/debug.hxx> 28 #include <tools/diagnose_ex.h> 29 #include <canvas/verbosetrace.hxx> 30 31 #include "drawshapesubsetting.hxx" 32 #include "subsettableshapemanager.hxx" 33 #include "eventqueue.hxx" 34 #include "eventmultiplexer.hxx" 35 #include "intrinsicanimationactivity.hxx" 36 #include "intrinsicanimationeventhandler.hxx" 37 38 #include <boost/noncopyable.hpp> 39 #include <boost/enable_shared_from_this.hpp> 40 #include <boost/weak_ptr.hpp> 41 42 namespace slideshow 43 { 44 namespace internal 45 { 46 /** Activity for intrinsic shape animations 47 48 This is an Activity interface implementation for intrinsic 49 shape animations. Intrinsic shape animations are 50 animations directly within a shape, e.g. drawing layer 51 animations, or GIF animations. 52 */ 53 class IntrinsicAnimationActivity : public Activity, 54 public boost::enable_shared_from_this<IntrinsicAnimationActivity>, 55 private boost::noncopyable 56 { 57 public: 58 /** Create an IntrinsicAnimationActivity. 59 60 @param rContext 61 Common slideshow objects 62 63 @param rDrawShape 64 Shape to control the intrinsic animation for 65 66 @param rWakeupEvent 67 Externally generated wakeup event, to set this 68 activity to sleep during inter-frame intervals. Must 69 come frome the outside, since wakeup event and this 70 object have mutual references to each other. 71 72 @param rTimeouts 73 Vector of timeout values, to wait before the next 74 frame is shown. 75 */ 76 IntrinsicAnimationActivity( const SlideShowContext& rContext, 77 const DrawShapeSharedPtr& rDrawShape, 78 const WakeupEventSharedPtr& rWakeupEvent, 79 const ::std::vector<double>& rTimeouts, 80 ::std::size_t nNumLoops, 81 CycleMode eCycleMode ); 82 83 virtual void dispose(); 84 virtual double calcTimeLag() const; 85 virtual bool perform(); 86 virtual bool isActive() const; 87 virtual void dequeued(); 88 virtual void end(); 89 90 bool enableAnimations(); 91 92 private: 93 SlideShowContext maContext; 94 boost::weak_ptr<DrawShape> mpDrawShape; 95 WakeupEventSharedPtr mpWakeupEvent; 96 IntrinsicAnimationEventHandlerSharedPtr mpListener; 97 ::std::vector<double> maTimeouts; 98 CycleMode meCycleMode; 99 ::std::size_t mnCurrIndex; 100 ::std::size_t mnNumLoops; 101 ::std::size_t mnLoopCount; 102 bool mbIsActive; 103 }; 104 105 ////////////////////////////////////////////////////////////////////// 106 107 class IntrinsicAnimationListener : public IntrinsicAnimationEventHandler, 108 private boost::noncopyable 109 { 110 public: 111 explicit IntrinsicAnimationListener( IntrinsicAnimationActivity& rActivity ) : 112 mrActivity( rActivity ) 113 {} 114 115 private: 116 117 virtual bool enableAnimations() { return mrActivity.enableAnimations(); } 118 virtual bool disableAnimations() { mrActivity.end(); return true; } 119 120 IntrinsicAnimationActivity& mrActivity; 121 }; 122 123 ////////////////////////////////////////////////////////////////////// 124 125 IntrinsicAnimationActivity::IntrinsicAnimationActivity( const SlideShowContext& rContext, 126 const DrawShapeSharedPtr& rDrawShape, 127 const WakeupEventSharedPtr& rWakeupEvent, 128 const ::std::vector<double>& rTimeouts, 129 ::std::size_t nNumLoops, 130 CycleMode eCycleMode ) : 131 maContext( rContext ), 132 mpDrawShape( rDrawShape ), 133 mpWakeupEvent( rWakeupEvent ), 134 mpListener( new IntrinsicAnimationListener(*this) ), 135 maTimeouts( rTimeouts ), 136 meCycleMode( eCycleMode ), 137 mnCurrIndex(0), 138 mnNumLoops(nNumLoops), 139 mnLoopCount(0), 140 mbIsActive(false) 141 { 142 ENSURE_OR_THROW( rContext.mpSubsettableShapeManager, 143 "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid shape manager" ); 144 ENSURE_OR_THROW( rDrawShape, 145 "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid draw shape" ); 146 ENSURE_OR_THROW( rWakeupEvent, 147 "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Invalid wakeup event" ); 148 ENSURE_OR_THROW( !rTimeouts.empty(), 149 "IntrinsicAnimationActivity::IntrinsicAnimationActivity(): Empty timeout vector" ); 150 151 maContext.mpSubsettableShapeManager->addIntrinsicAnimationHandler( 152 mpListener ); 153 } 154 155 void IntrinsicAnimationActivity::dispose() 156 { 157 end(); 158 159 if( mpWakeupEvent ) 160 mpWakeupEvent->dispose(); 161 162 maContext.dispose(); 163 mpDrawShape.reset(); 164 mpWakeupEvent.reset(); 165 maTimeouts.clear(); 166 mnCurrIndex = 0; 167 168 maContext.mpSubsettableShapeManager->removeIntrinsicAnimationHandler( 169 mpListener ); 170 } 171 172 double IntrinsicAnimationActivity::calcTimeLag() const 173 { 174 return 0.0; 175 } 176 177 bool IntrinsicAnimationActivity::perform() 178 { 179 if( !isActive() ) 180 return false; 181 182 DrawShapeSharedPtr pDrawShape( mpDrawShape.lock() ); 183 if( !pDrawShape || !mpWakeupEvent ) 184 { 185 // event or draw shape vanished, no sense living on -> 186 // commit suicide. 187 dispose(); 188 return false; 189 } 190 191 // mnNumLoops == 0 means infinite looping 192 if( mnNumLoops != 0 && 193 mnLoopCount >= mnNumLoops ) 194 { 195 // #i55294# After finishing the loops, display the first frame 196 pDrawShape->setIntrinsicAnimationFrame( 0 ); 197 maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape ); 198 199 end(); 200 201 return false; 202 } 203 204 ::std::size_t nNewIndex = 0; 205 const ::std::size_t nNumFrames(maTimeouts.size()); 206 switch( meCycleMode ) 207 { 208 case CYCLE_LOOP: 209 { 210 pDrawShape->setIntrinsicAnimationFrame( mnCurrIndex ); 211 212 mpWakeupEvent->start(); 213 mpWakeupEvent->setNextTimeout( maTimeouts[mnCurrIndex] ); 214 215 mnLoopCount += (mnCurrIndex + 1) / nNumFrames; 216 nNewIndex = (mnCurrIndex + 1) % nNumFrames; 217 break; 218 } 219 220 case CYCLE_PINGPONGLOOP: 221 { 222 ::std::size_t nTrueIndex( mnCurrIndex < nNumFrames ? 223 mnCurrIndex : 224 2*nNumFrames - mnCurrIndex - 1 ); 225 pDrawShape->setIntrinsicAnimationFrame( nTrueIndex ); 226 227 mpWakeupEvent->start(); 228 mpWakeupEvent->setNextTimeout( maTimeouts[nTrueIndex] ); 229 230 mnLoopCount += (mnCurrIndex + 1) / (2*nNumFrames); 231 nNewIndex = (mnCurrIndex + 1) % 2*nNumFrames; 232 break; 233 } 234 } 235 236 maContext.mrEventQueue.addEvent( mpWakeupEvent ); 237 maContext.mpSubsettableShapeManager->notifyShapeUpdate( pDrawShape ); 238 mnCurrIndex = nNewIndex; 239 240 return false; // don't reinsert, WakeupEvent will perform 241 // that after the given timeout 242 } 243 244 bool IntrinsicAnimationActivity::isActive() const 245 { 246 return mbIsActive; 247 } 248 249 void IntrinsicAnimationActivity::dequeued() 250 { 251 // not used here 252 } 253 254 void IntrinsicAnimationActivity::end() 255 { 256 // there is no dedicated end state, just become inactive: 257 mbIsActive = false; 258 } 259 260 bool IntrinsicAnimationActivity::enableAnimations() 261 { 262 mbIsActive = true; 263 return maContext.mrActivitiesQueue.addActivity( 264 shared_from_this() ); 265 } 266 267 ////////////////////////////////////////////////////////////////////// 268 269 ActivitySharedPtr createIntrinsicAnimationActivity( 270 const SlideShowContext& rContext, 271 const DrawShapeSharedPtr& rDrawShape, 272 const WakeupEventSharedPtr& rWakeupEvent, 273 const ::std::vector<double>& rTimeouts, 274 ::std::size_t nNumLoops, 275 CycleMode eCycleMode ) 276 { 277 return ActivitySharedPtr( 278 new IntrinsicAnimationActivity(rContext, 279 rDrawShape, 280 rWakeupEvent, 281 rTimeouts, 282 nNumLoops, 283 eCycleMode) ); 284 } 285 } 286 } 287