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