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 #include <canvas/canvastools.hxx>
36 
37 #include <activitybase.hxx>
38 
39 
40 namespace slideshow
41 {
42     namespace internal
43     {
44         // TODO(P1): Elide some virtual function calls, by templifying this
45         // static hierarchy
46 
47         ActivityBase::ActivityBase( const ActivityParameters& rParms ) :
48             mpEndEvent( rParms.mrEndEvent ),
49             mrEventQueue( rParms.mrEventQueue ),
50             mpShape(),
51             mpAttributeLayer(),
52             maRepeats( rParms.mrRepeats ),
53             mnAccelerationFraction( rParms.mnAccelerationFraction ),
54             mnDecelerationFraction( rParms.mnDecelerationFraction ),
55             mbAutoReverse( rParms.mbAutoReverse ),
56             mbFirstPerformCall( true ),
57             mbIsActive( true ) {}
58 
59         void ActivityBase::dispose()
60         {
61             // deactivate
62             mbIsActive = false;
63 
64             // dispose event
65             if( mpEndEvent )
66                 mpEndEvent->dispose();
67 
68             // release references
69             mpEndEvent.reset();
70             mpShape.reset();
71             mpAttributeLayer.reset();
72         }
73 
74         double ActivityBase::calcTimeLag() const
75         {
76             // TODO(Q1): implement different init process!
77             if (isActive() && mbFirstPerformCall)
78             {
79                 mbFirstPerformCall = false;
80 
81                 // notify derived classes that we're
82                 // starting now
83                 const_cast<ActivityBase *>(this)->startAnimation();
84             }
85             return 0.0;
86         }
87 
88         bool ActivityBase::perform()
89         {
90             // still active?
91             if( !isActive() )
92                 return false; // no, early exit.
93 
94             OSL_ASSERT( ! mbFirstPerformCall );
95 
96             return true;
97         }
98 
99         bool ActivityBase::isActive() const
100         {
101             return mbIsActive;
102         }
103 
104         void ActivityBase::setTargets( const AnimatableShapeSharedPtr& 		rShape,
105                                        const ShapeAttributeLayerSharedPtr& 	rAttrLayer )
106         {
107             ENSURE_OR_THROW( rShape,
108                               "ActivityBase::setTargets(): Invalid shape" );
109             ENSURE_OR_THROW( rAttrLayer,
110                               "ActivityBase::setTargets(): Invalid attribute layer" );
111 
112             mpShape = rShape;
113             mpAttributeLayer = rAttrLayer;
114         }
115 
116         void ActivityBase::endActivity()
117         {
118             // this is a regular activity end
119             mbIsActive = false;
120 
121             // Activity is ending, queue event, then
122             if( mpEndEvent )
123                 mrEventQueue.addEvent( mpEndEvent );
124 
125             // release references
126             mpEndEvent.reset();
127         }
128 
129         void ActivityBase::dequeued()
130         {
131             // xxx todo:
132 //             // ignored here, if we're still active. Discrete
133 //             // activities are dequeued after every perform() call,
134 //             // thus, the call is only significant when isActive() ==
135 //             // false.
136             if( !isActive() )
137                 endAnimation();
138         }
139 
140         void ActivityBase::end()
141         {
142             if (!isActive() || isDisposed())
143                 return;
144             // assure animation is started:
145             if (mbFirstPerformCall) {
146                 mbFirstPerformCall = false;
147                 // notify derived classes that we're starting now
148                 this->startAnimation();
149             }
150 
151             performEnd(); // calling private virtual
152             endAnimation();
153             endActivity();
154         }
155 
156         double ActivityBase::calcAcceleratedTime( double nT ) const
157         {
158             // Handle acceleration/deceleration
159             // ================================
160 
161             // clamp nT to permissible [0,1] range
162             nT = ::basegfx::clamp( nT, 0.0, 1.0 );
163 
164             // take acceleration/deceleration into account. if the sum
165             // of mnAccelerationFraction and mnDecelerationFraction
166             // exceeds 1.0, ignore both (that's according to SMIL spec)
167             if( (mnAccelerationFraction > 0.0 ||
168                  mnDecelerationFraction > 0.0) &&
169                 mnAccelerationFraction + mnDecelerationFraction <= 1.0 )
170             {
171                 /*
172                 // calc accelerated/decelerated time.
173                 //
174                 // We have three intervals:
175                 // 1 [0,a]
176                 // 2 [a,d]
177                 // 3 [d,1] (with a and d being acceleration/deceleration
178                 // fraction, resp.)
179                 //
180                 // The change rate during interval 1 is constantly
181                 // increasing, reaching 1 at a. It then stays at 1,
182                 // starting a linear decrease at d, ending with 0 at
183                 // time 1. The integral of this function is the
184                 // required new time nT'.
185                 //
186                 // As we arbitrarily assumed 1 as the upper value of
187                 // the change rate, the integral must be normalized to
188                 // reach nT'=1 at the end of the interval. This
189                 // normalization constant is:
190                 //
191                 // c = 1 - 0.5a - 0.5d
192                 //
193                 // The integral itself then amounts to:
194                 //
195                 // 0.5 nT^2 / a + (nT-a) + (nT - 0.5 nT^2 / d)
196                 //
197                 // (where each of the three summands correspond to the
198                 // three intervals above, and are applied only if nT
199                 // has reached the corresponding interval)
200                 //
201                 // The graph of the change rate is a trapezoid:
202                 //
203                 //   |
204                 //  1|      /--------------\
205                 //   |     /                \
206                 //   |    /                  \
207                 //   |   /                    \
208                 //   -----------------------------
209                 //      0   a              d  1
210                 //
211                 //*/
212                 const double nC( 1.0 - 0.5*mnAccelerationFraction - 0.5*mnDecelerationFraction );
213 
214                 // this variable accumulates the new time value
215                 double nTPrime(0.0);
216 
217                 if( nT < mnAccelerationFraction )
218                 {
219                     nTPrime += 0.5*nT*nT/mnAccelerationFraction; // partial first interval
220                 }
221                 else
222                 {
223                     nTPrime += 0.5*mnAccelerationFraction; // full first interval
224 
225                     if( nT <= 1.0-mnDecelerationFraction )
226                     {
227                         nTPrime += nT-mnAccelerationFraction; // partial second interval
228                     }
229                     else
230                     {
231                         nTPrime += 1.0 - mnAccelerationFraction - mnDecelerationFraction; // full second interval
232 
233                         const double nTRelative( nT - 1.0 + mnDecelerationFraction );
234 
235                         nTPrime += nTRelative - 0.5*nTRelative*nTRelative / mnDecelerationFraction;
236                     }
237                 }
238 
239                 // normalize, and assign to work variable
240                 nT = nTPrime / nC;
241             }
242 
243             return nT;
244         }
245     }
246 }
247