1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir // must be first 32*cdf0e10cSrcweir #include <canvas/debug.hxx> 33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 34*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx> 35*cdf0e10cSrcweir #include <comphelper/anytostring.hxx> 36*cdf0e10cSrcweir #include <com/sun/star/presentation/ParagraphTarget.hpp> 37*cdf0e10cSrcweir #include <com/sun/star/animations/Timing.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/animations/AnimationAdditiveMode.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/presentation/ShapeAnimationSubType.hpp> 40*cdf0e10cSrcweir 41*cdf0e10cSrcweir #include "nodetools.hxx" 42*cdf0e10cSrcweir #include "doctreenode.hxx" 43*cdf0e10cSrcweir #include "animationbasenode.hxx" 44*cdf0e10cSrcweir #include "delayevent.hxx" 45*cdf0e10cSrcweir #include "framerate.hxx" 46*cdf0e10cSrcweir 47*cdf0e10cSrcweir #include <boost/bind.hpp> 48*cdf0e10cSrcweir #include <boost/optional.hpp> 49*cdf0e10cSrcweir #include <algorithm> 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir using namespace com::sun::star; 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir namespace slideshow { 54*cdf0e10cSrcweir namespace internal { 55*cdf0e10cSrcweir 56*cdf0e10cSrcweir AnimationBaseNode::AnimationBaseNode( 57*cdf0e10cSrcweir const uno::Reference< animations::XAnimationNode >& xNode, 58*cdf0e10cSrcweir const BaseContainerNodeSharedPtr& rParent, 59*cdf0e10cSrcweir const NodeContext& rContext ) 60*cdf0e10cSrcweir : BaseNode( xNode, rParent, rContext ), 61*cdf0e10cSrcweir mxAnimateNode( xNode, uno::UNO_QUERY_THROW ), 62*cdf0e10cSrcweir maAttributeLayerHolder(), 63*cdf0e10cSrcweir maSlideSize( rContext.maSlideSize ), 64*cdf0e10cSrcweir mpActivity(), 65*cdf0e10cSrcweir mpShape(), 66*cdf0e10cSrcweir mpShapeSubset(), 67*cdf0e10cSrcweir mpSubsetManager(rContext.maContext.mpSubsettableShapeManager), 68*cdf0e10cSrcweir mbIsIndependentSubset( rContext.mbIsIndependentSubset ) 69*cdf0e10cSrcweir { 70*cdf0e10cSrcweir // extract native node targets 71*cdf0e10cSrcweir // =========================== 72*cdf0e10cSrcweir 73*cdf0e10cSrcweir // plain shape target 74*cdf0e10cSrcweir uno::Reference< drawing::XShape > xShape( mxAnimateNode->getTarget(), 75*cdf0e10cSrcweir uno::UNO_QUERY ); 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir // distinguish 5 cases: 78*cdf0e10cSrcweir // 79*cdf0e10cSrcweir // - plain shape target 80*cdf0e10cSrcweir // (NodeContext.mpMasterShapeSubset full set) 81*cdf0e10cSrcweir // 82*cdf0e10cSrcweir // - parent-generated subset (generate an 83*cdf0e10cSrcweir // independent subset) 84*cdf0e10cSrcweir // 85*cdf0e10cSrcweir // - parent-generated subset from iteration 86*cdf0e10cSrcweir // (generate a dependent subset) 87*cdf0e10cSrcweir // 88*cdf0e10cSrcweir // - XShape target at the XAnimatioNode (generate 89*cdf0e10cSrcweir // a plain shape target) 90*cdf0e10cSrcweir // 91*cdf0e10cSrcweir // - ParagraphTarget target at the XAnimationNode 92*cdf0e10cSrcweir // (generate an independent shape subset) 93*cdf0e10cSrcweir if( rContext.mpMasterShapeSubset ) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir if( rContext.mpMasterShapeSubset->isFullSet() ) 96*cdf0e10cSrcweir { 97*cdf0e10cSrcweir // case 1: plain shape target from parent 98*cdf0e10cSrcweir mpShape = rContext.mpMasterShapeSubset->getSubsetShape(); 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir else 101*cdf0e10cSrcweir { 102*cdf0e10cSrcweir // cases 2 & 3: subset shape 103*cdf0e10cSrcweir mpShapeSubset = rContext.mpMasterShapeSubset; 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir } 106*cdf0e10cSrcweir else 107*cdf0e10cSrcweir { 108*cdf0e10cSrcweir // no parent-provided shape, try to extract 109*cdf0e10cSrcweir // from XAnimationNode - cases 4 and 5 110*cdf0e10cSrcweir 111*cdf0e10cSrcweir if( xShape.is() ) 112*cdf0e10cSrcweir { 113*cdf0e10cSrcweir mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager, 114*cdf0e10cSrcweir xShape ); 115*cdf0e10cSrcweir } 116*cdf0e10cSrcweir else 117*cdf0e10cSrcweir { 118*cdf0e10cSrcweir // no shape provided. Maybe a ParagraphTarget? 119*cdf0e10cSrcweir presentation::ParagraphTarget aTarget; 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir if( !(mxAnimateNode->getTarget() >>= aTarget) ) 122*cdf0e10cSrcweir ENSURE_OR_THROW( 123*cdf0e10cSrcweir false, "could not extract any target information" ); 124*cdf0e10cSrcweir 125*cdf0e10cSrcweir xShape = aTarget.Shape; 126*cdf0e10cSrcweir 127*cdf0e10cSrcweir ENSURE_OR_THROW( xShape.is(), "invalid shape in ParagraphTarget" ); 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir mpShape = lookupAttributableShape( getContext().mpSubsettableShapeManager, 130*cdf0e10cSrcweir xShape ); 131*cdf0e10cSrcweir 132*cdf0e10cSrcweir // NOTE: For shapes with ParagraphTarget, we ignore 133*cdf0e10cSrcweir // the SubItem property. We implicitely assume that it 134*cdf0e10cSrcweir // is set to ONLY_TEXT. 135*cdf0e10cSrcweir OSL_ENSURE( 136*cdf0e10cSrcweir mxAnimateNode->getSubItem() == 137*cdf0e10cSrcweir presentation::ShapeAnimationSubType::ONLY_TEXT || 138*cdf0e10cSrcweir mxAnimateNode->getSubItem() == 139*cdf0e10cSrcweir presentation::ShapeAnimationSubType::AS_WHOLE, 140*cdf0e10cSrcweir "ParagraphTarget given, but subitem not AS_TEXT or AS_WHOLE? " 141*cdf0e10cSrcweir "Make up your mind, I'll ignore the subitem." ); 142*cdf0e10cSrcweir 143*cdf0e10cSrcweir // okay, found a ParagraphTarget with a valid XShape. Does the shape 144*cdf0e10cSrcweir // provide the given paragraph? 145*cdf0e10cSrcweir const DocTreeNode& rTreeNode( 146*cdf0e10cSrcweir mpShape->getTreeNodeSupplier().getTreeNode( 147*cdf0e10cSrcweir aTarget.Paragraph, 148*cdf0e10cSrcweir DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH ) ); 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir // CAUTION: the creation of the subset shape 151*cdf0e10cSrcweir // _must_ stay in the node constructor, since 152*cdf0e10cSrcweir // Slide::prefetchShow() initializes shape 153*cdf0e10cSrcweir // attributes right after animation import (or 154*cdf0e10cSrcweir // the Slide class must be changed). 155*cdf0e10cSrcweir mpShapeSubset.reset( 156*cdf0e10cSrcweir new ShapeSubset( mpShape, 157*cdf0e10cSrcweir rTreeNode, 158*cdf0e10cSrcweir mpSubsetManager )); 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir // Override NodeContext, and flag this node as 161*cdf0e10cSrcweir // a special independent subset one. This is 162*cdf0e10cSrcweir // important when applying initial attributes: 163*cdf0e10cSrcweir // independent shape subsets must be setup 164*cdf0e10cSrcweir // when the slide starts, since they, as their 165*cdf0e10cSrcweir // name suggest, can have state independent to 166*cdf0e10cSrcweir // the master shape. The following example 167*cdf0e10cSrcweir // might illustrate that: a master shape has 168*cdf0e10cSrcweir // no effect, one of the text paragraphs 169*cdf0e10cSrcweir // within it has an appear effect. Now, the 170*cdf0e10cSrcweir // respective paragraph must be invisible when 171*cdf0e10cSrcweir // the slide is initially shown, and become 172*cdf0e10cSrcweir // visible only when the effect starts. 173*cdf0e10cSrcweir mbIsIndependentSubset = true; 174*cdf0e10cSrcweir 175*cdf0e10cSrcweir // already enable subset right here, the 176*cdf0e10cSrcweir // setup of initial shape attributes of 177*cdf0e10cSrcweir // course needs the subset shape 178*cdf0e10cSrcweir // generated, to apply e.g. visibility 179*cdf0e10cSrcweir // changes. 180*cdf0e10cSrcweir mpShapeSubset->enableSubsetShape(); 181*cdf0e10cSrcweir } 182*cdf0e10cSrcweir } 183*cdf0e10cSrcweir } 184*cdf0e10cSrcweir 185*cdf0e10cSrcweir void AnimationBaseNode::dispose() 186*cdf0e10cSrcweir { 187*cdf0e10cSrcweir if (mpActivity) { 188*cdf0e10cSrcweir mpActivity->dispose(); 189*cdf0e10cSrcweir mpActivity.reset(); 190*cdf0e10cSrcweir } 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir maAttributeLayerHolder.reset(); 193*cdf0e10cSrcweir mxAnimateNode.clear(); 194*cdf0e10cSrcweir mpShape.reset(); 195*cdf0e10cSrcweir mpShapeSubset.reset(); 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir BaseNode::dispose(); 198*cdf0e10cSrcweir } 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir bool AnimationBaseNode::init_st() 201*cdf0e10cSrcweir { 202*cdf0e10cSrcweir // if we've still got an old activity lying around, dispose it: 203*cdf0e10cSrcweir if (mpActivity) { 204*cdf0e10cSrcweir mpActivity->dispose(); 205*cdf0e10cSrcweir mpActivity.reset(); 206*cdf0e10cSrcweir } 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir // note: actually disposing the activity too early might cause problems, 209*cdf0e10cSrcweir // because on dequeued() it calls endAnimation(pAnim->end()), thus ending 210*cdf0e10cSrcweir // animation _after_ last screen update. 211*cdf0e10cSrcweir // review that end() is properly called (which calls endAnimation(), too). 212*cdf0e10cSrcweir 213*cdf0e10cSrcweir try { 214*cdf0e10cSrcweir // TODO(F2): For restart functionality, we must regenerate activities, 215*cdf0e10cSrcweir // since they are not able to reset their state (or implement _that_) 216*cdf0e10cSrcweir mpActivity = createActivity(); 217*cdf0e10cSrcweir } 218*cdf0e10cSrcweir catch (uno::Exception const&) { 219*cdf0e10cSrcweir OSL_ENSURE( false, rtl::OUStringToOString( 220*cdf0e10cSrcweir comphelper::anyToString(cppu::getCaughtException()), 221*cdf0e10cSrcweir RTL_TEXTENCODING_UTF8 ) ); 222*cdf0e10cSrcweir // catch and ignore. We later handle empty activities, but for 223*cdf0e10cSrcweir // other nodes to function properly, the core functionality of 224*cdf0e10cSrcweir // this node must remain up and running. 225*cdf0e10cSrcweir } 226*cdf0e10cSrcweir return true; 227*cdf0e10cSrcweir } 228*cdf0e10cSrcweir 229*cdf0e10cSrcweir bool AnimationBaseNode::resolve_st() 230*cdf0e10cSrcweir { 231*cdf0e10cSrcweir // enable shape subset for automatically generated 232*cdf0e10cSrcweir // subsets. Independent subsets are already setup 233*cdf0e10cSrcweir // during construction time. Doing it only here 234*cdf0e10cSrcweir // saves us a lot of sprites and shapes lying 235*cdf0e10cSrcweir // around. This is especially important for 236*cdf0e10cSrcweir // character-wise iterations, since the shape 237*cdf0e10cSrcweir // content (e.g. thousands of characters) would 238*cdf0e10cSrcweir // otherwise be painted character-by-character. 239*cdf0e10cSrcweir if (isDependentSubsettedShape() && mpShapeSubset) { 240*cdf0e10cSrcweir mpShapeSubset->enableSubsetShape(); 241*cdf0e10cSrcweir } 242*cdf0e10cSrcweir return true; 243*cdf0e10cSrcweir } 244*cdf0e10cSrcweir 245*cdf0e10cSrcweir void AnimationBaseNode::activate_st() 246*cdf0e10cSrcweir { 247*cdf0e10cSrcweir // create new attribute layer 248*cdf0e10cSrcweir maAttributeLayerHolder.createAttributeLayer( getShape() ); 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir ENSURE_OR_THROW( maAttributeLayerHolder.get(), 251*cdf0e10cSrcweir "Could not generate shape attribute layer" ); 252*cdf0e10cSrcweir 253*cdf0e10cSrcweir // TODO(Q2): This affects the way mpActivity 254*cdf0e10cSrcweir // works, but is performed here because of 255*cdf0e10cSrcweir // locality (we're fiddling with the additive mode 256*cdf0e10cSrcweir // here, anyway, and it's the only place where we 257*cdf0e10cSrcweir // do). OTOH, maybe the complete additive mode 258*cdf0e10cSrcweir // setup should be moved to the activities. 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir // for simple by-animations, the SMIL spec 261*cdf0e10cSrcweir // requires us to emulate "0,by-value" value list 262*cdf0e10cSrcweir // behaviour, with additive mode forced to "sum", 263*cdf0e10cSrcweir // no matter what the input is 264*cdf0e10cSrcweir // (http://www.w3.org/TR/smil20/animation.html#adef-by). 265*cdf0e10cSrcweir if( mxAnimateNode->getBy().hasValue() && 266*cdf0e10cSrcweir !mxAnimateNode->getTo().hasValue() && 267*cdf0e10cSrcweir !mxAnimateNode->getFrom().hasValue() ) 268*cdf0e10cSrcweir { 269*cdf0e10cSrcweir // force attribute mode to REPLACE (note the 270*cdf0e10cSrcweir // subtle discrepancy to the paragraph above, 271*cdf0e10cSrcweir // where SMIL requires SUM. This is internally 272*cdf0e10cSrcweir // handled by the FromToByActivity, and is 273*cdf0e10cSrcweir // because otherwise DOM values would not be 274*cdf0e10cSrcweir // handled correctly: the activity cannot 275*cdf0e10cSrcweir // determine whether an 276*cdf0e10cSrcweir // Activity::getUnderlyingValue() yields the 277*cdf0e10cSrcweir // DOM value, or already a summed-up conglomerate) 278*cdf0e10cSrcweir // 279*cdf0e10cSrcweir // Note that this poses problems with our 280*cdf0e10cSrcweir // hybrid activity duration (time or min number of frames), 281*cdf0e10cSrcweir // since if activities 282*cdf0e10cSrcweir // exceed their duration, wrong 'by' start 283*cdf0e10cSrcweir // values might arise ('Laser effect') 284*cdf0e10cSrcweir maAttributeLayerHolder.get()->setAdditiveMode( 285*cdf0e10cSrcweir animations::AnimationAdditiveMode::REPLACE ); 286*cdf0e10cSrcweir } 287*cdf0e10cSrcweir else 288*cdf0e10cSrcweir { 289*cdf0e10cSrcweir // apply additive mode to newly created Attribute layer 290*cdf0e10cSrcweir maAttributeLayerHolder.get()->setAdditiveMode( 291*cdf0e10cSrcweir mxAnimateNode->getAdditive() ); 292*cdf0e10cSrcweir } 293*cdf0e10cSrcweir 294*cdf0e10cSrcweir // fake normal animation behaviour, even if we 295*cdf0e10cSrcweir // show nothing. This is the appropriate way to 296*cdf0e10cSrcweir // handle errors on Activity generation, because 297*cdf0e10cSrcweir // maybe all other effects on the slide are 298*cdf0e10cSrcweir // correctly initialized (but won't run, if we 299*cdf0e10cSrcweir // signal an error here) 300*cdf0e10cSrcweir if (mpActivity) { 301*cdf0e10cSrcweir // supply Activity (and the underlying Animation) with 302*cdf0e10cSrcweir // it's AttributeLayer, to perform the animation on 303*cdf0e10cSrcweir mpActivity->setTargets( getShape(), maAttributeLayerHolder.get() ); 304*cdf0e10cSrcweir 305*cdf0e10cSrcweir // add to activities queue 306*cdf0e10cSrcweir getContext().mrActivitiesQueue.addActivity( mpActivity ); 307*cdf0e10cSrcweir } 308*cdf0e10cSrcweir else { 309*cdf0e10cSrcweir // Actually, DO generate the event for empty activity, 310*cdf0e10cSrcweir // to keep the chain of animations running 311*cdf0e10cSrcweir BaseNode::scheduleDeactivationEvent(); 312*cdf0e10cSrcweir } 313*cdf0e10cSrcweir } 314*cdf0e10cSrcweir 315*cdf0e10cSrcweir void AnimationBaseNode::deactivate_st( NodeState eDestState ) 316*cdf0e10cSrcweir { 317*cdf0e10cSrcweir if (eDestState == FROZEN) { 318*cdf0e10cSrcweir if (mpActivity) 319*cdf0e10cSrcweir mpActivity->end(); 320*cdf0e10cSrcweir } 321*cdf0e10cSrcweir 322*cdf0e10cSrcweir if (isDependentSubsettedShape()) { 323*cdf0e10cSrcweir // for dependent subsets, remove subset shape 324*cdf0e10cSrcweir // from layer, re-integrate subsetted part 325*cdf0e10cSrcweir // back into original shape. For independent 326*cdf0e10cSrcweir // subsets, we cannot make any assumptions 327*cdf0e10cSrcweir // about subset attribute state relative to 328*cdf0e10cSrcweir // master shape, thus, have to keep it. This 329*cdf0e10cSrcweir // will effectively re-integrate the subsetted 330*cdf0e10cSrcweir // part into the original shape (whose 331*cdf0e10cSrcweir // animation will hopefully have ended, too) 332*cdf0e10cSrcweir 333*cdf0e10cSrcweir // this statement will save a whole lot of 334*cdf0e10cSrcweir // sprites for iterated text effects, since 335*cdf0e10cSrcweir // those sprites will only exist during the 336*cdf0e10cSrcweir // actual lifetime of the effects 337*cdf0e10cSrcweir if (mpShapeSubset) { 338*cdf0e10cSrcweir mpShapeSubset->disableSubsetShape(); 339*cdf0e10cSrcweir } 340*cdf0e10cSrcweir } 341*cdf0e10cSrcweir 342*cdf0e10cSrcweir if (eDestState == ENDED) { 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir // no shape anymore, no layer needed: 345*cdf0e10cSrcweir maAttributeLayerHolder.reset(); 346*cdf0e10cSrcweir 347*cdf0e10cSrcweir if (! isDependentSubsettedShape()) { 348*cdf0e10cSrcweir 349*cdf0e10cSrcweir // for all other shapes, removing the 350*cdf0e10cSrcweir // attribute layer quite possibly changes 351*cdf0e10cSrcweir // shape display. Thus, force update 352*cdf0e10cSrcweir AttributableShapeSharedPtr const pShape( getShape() ); 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir // don't anybody dare to check against 355*cdf0e10cSrcweir // pShape->isVisible() here, removing the 356*cdf0e10cSrcweir // attribute layer might actually make the 357*cdf0e10cSrcweir // shape invisible! 358*cdf0e10cSrcweir getContext().mpSubsettableShapeManager->notifyShapeUpdate( pShape ); 359*cdf0e10cSrcweir } 360*cdf0e10cSrcweir 361*cdf0e10cSrcweir if (mpActivity) { 362*cdf0e10cSrcweir // kill activity, if still running 363*cdf0e10cSrcweir mpActivity->dispose(); 364*cdf0e10cSrcweir mpActivity.reset(); 365*cdf0e10cSrcweir } 366*cdf0e10cSrcweir } 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir 369*cdf0e10cSrcweir bool AnimationBaseNode::hasPendingAnimation() const 370*cdf0e10cSrcweir { 371*cdf0e10cSrcweir // TODO(F1): This might not always be true. Are there 'inactive' 372*cdf0e10cSrcweir // animation nodes? 373*cdf0e10cSrcweir return true; 374*cdf0e10cSrcweir } 375*cdf0e10cSrcweir 376*cdf0e10cSrcweir #if defined(VERBOSE) && defined(DBG_UTIL) 377*cdf0e10cSrcweir void AnimationBaseNode::showState() const 378*cdf0e10cSrcweir { 379*cdf0e10cSrcweir BaseNode::showState(); 380*cdf0e10cSrcweir 381*cdf0e10cSrcweir VERBOSE_TRACE( "AnimationBaseNode info: independent subset=%s", 382*cdf0e10cSrcweir mbIsIndependentSubset ? "y" : "n" ); 383*cdf0e10cSrcweir } 384*cdf0e10cSrcweir #endif 385*cdf0e10cSrcweir 386*cdf0e10cSrcweir ActivitiesFactory::CommonParameters 387*cdf0e10cSrcweir AnimationBaseNode::fillCommonParameters() const 388*cdf0e10cSrcweir { 389*cdf0e10cSrcweir double nDuration = 0.0; 390*cdf0e10cSrcweir 391*cdf0e10cSrcweir // TODO(F3): Duration/End handling is barely there 392*cdf0e10cSrcweir if( !(mxAnimateNode->getDuration() >>= nDuration) ) { 393*cdf0e10cSrcweir mxAnimateNode->getEnd() >>= nDuration; // Wah. 394*cdf0e10cSrcweir } 395*cdf0e10cSrcweir 396*cdf0e10cSrcweir // minimal duration we fallback to (avoid 0 here!) 397*cdf0e10cSrcweir nDuration = ::std::max( 0.001, nDuration ); 398*cdf0e10cSrcweir 399*cdf0e10cSrcweir const bool bAutoReverse( mxAnimateNode->getAutoReverse() ); 400*cdf0e10cSrcweir 401*cdf0e10cSrcweir boost::optional<double> aRepeats; 402*cdf0e10cSrcweir double nRepeats = 0; 403*cdf0e10cSrcweir if( (mxAnimateNode->getRepeatCount() >>= nRepeats) ) { 404*cdf0e10cSrcweir aRepeats.reset( nRepeats ); 405*cdf0e10cSrcweir } 406*cdf0e10cSrcweir else { 407*cdf0e10cSrcweir if( (mxAnimateNode->getRepeatDuration() >>= nRepeats) ) { 408*cdf0e10cSrcweir // when repeatDuration is given, 409*cdf0e10cSrcweir // autoreverse does _not_ modify the 410*cdf0e10cSrcweir // active duration. Thus, calc repeat 411*cdf0e10cSrcweir // count with already adapted simple 412*cdf0e10cSrcweir // duration (twice the specified duration) 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir // convert duration back to repeat counts 415*cdf0e10cSrcweir if( bAutoReverse ) 416*cdf0e10cSrcweir aRepeats.reset( nRepeats / (2.0 * nDuration) ); 417*cdf0e10cSrcweir else 418*cdf0e10cSrcweir aRepeats.reset( nRepeats / nDuration ); 419*cdf0e10cSrcweir } 420*cdf0e10cSrcweir else { 421*cdf0e10cSrcweir // no double value for both values - Timing::INDEFINITE? 422*cdf0e10cSrcweir animations::Timing eTiming; 423*cdf0e10cSrcweir 424*cdf0e10cSrcweir if( !(mxAnimateNode->getRepeatDuration() >>= eTiming) || 425*cdf0e10cSrcweir eTiming != animations::Timing_INDEFINITE ) 426*cdf0e10cSrcweir { 427*cdf0e10cSrcweir if( !(mxAnimateNode->getRepeatCount() >>= eTiming) || 428*cdf0e10cSrcweir eTiming != animations::Timing_INDEFINITE ) 429*cdf0e10cSrcweir { 430*cdf0e10cSrcweir // no indefinite timing, no other values given - 431*cdf0e10cSrcweir // use simple run, i.e. repeat of 1.0 432*cdf0e10cSrcweir aRepeats.reset( 1.0 ); 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir } 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir } 437*cdf0e10cSrcweir 438*cdf0e10cSrcweir // calc accel/decel: 439*cdf0e10cSrcweir double nAcceleration = 0.0; 440*cdf0e10cSrcweir double nDeceleration = 0.0; 441*cdf0e10cSrcweir BaseNodeSharedPtr const pSelf( getSelf() ); 442*cdf0e10cSrcweir for ( boost::shared_ptr<BaseNode> pNode( pSelf ); 443*cdf0e10cSrcweir pNode; pNode = pNode->getParentNode() ) 444*cdf0e10cSrcweir { 445*cdf0e10cSrcweir uno::Reference<animations::XAnimationNode> const xAnimationNode( 446*cdf0e10cSrcweir pNode->getXAnimationNode() ); 447*cdf0e10cSrcweir nAcceleration = std::max( nAcceleration, 448*cdf0e10cSrcweir xAnimationNode->getAcceleration() ); 449*cdf0e10cSrcweir nDeceleration = std::max( nDeceleration, 450*cdf0e10cSrcweir xAnimationNode->getDecelerate() ); 451*cdf0e10cSrcweir } 452*cdf0e10cSrcweir 453*cdf0e10cSrcweir EventSharedPtr pEndEvent; 454*cdf0e10cSrcweir if (pSelf) { 455*cdf0e10cSrcweir pEndEvent = makeEvent( 456*cdf0e10cSrcweir boost::bind( &AnimationNode::deactivate, pSelf ), 457*cdf0e10cSrcweir "AnimationBaseNode::deactivate"); 458*cdf0e10cSrcweir } 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir // Calculate the minimum frame count that depends on the duration and 461*cdf0e10cSrcweir // the minimum frame count. 462*cdf0e10cSrcweir const sal_Int32 nMinFrameCount (basegfx::clamp<sal_Int32>( 463*cdf0e10cSrcweir basegfx::fround(nDuration * FrameRate::MinimumFramesPerSecond), 1, 10)); 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir return ActivitiesFactory::CommonParameters( 466*cdf0e10cSrcweir pEndEvent, 467*cdf0e10cSrcweir getContext().mrEventQueue, 468*cdf0e10cSrcweir getContext().mrActivitiesQueue, 469*cdf0e10cSrcweir nDuration, 470*cdf0e10cSrcweir nMinFrameCount, 471*cdf0e10cSrcweir bAutoReverse, 472*cdf0e10cSrcweir aRepeats, 473*cdf0e10cSrcweir nAcceleration, 474*cdf0e10cSrcweir nDeceleration, 475*cdf0e10cSrcweir getShape(), 476*cdf0e10cSrcweir getSlideSize()); 477*cdf0e10cSrcweir } 478*cdf0e10cSrcweir 479*cdf0e10cSrcweir AttributableShapeSharedPtr AnimationBaseNode::getShape() const 480*cdf0e10cSrcweir { 481*cdf0e10cSrcweir // any subsetting at all? 482*cdf0e10cSrcweir if (mpShapeSubset) 483*cdf0e10cSrcweir return mpShapeSubset->getSubsetShape(); 484*cdf0e10cSrcweir else 485*cdf0e10cSrcweir return mpShape; // nope, plain shape always 486*cdf0e10cSrcweir } 487*cdf0e10cSrcweir 488*cdf0e10cSrcweir } // namespace internal 489*cdf0e10cSrcweir } // namespace slideshow 490*cdf0e10cSrcweir 491