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_canvas.hxx"
26 
27 #include "osl/time.h"
28 #include "osl/diagnose.h"
29 #include "canvas/elapsedtime.hxx"
30 
31 #if defined(WNT)
32 
33 #if defined _MSC_VER
34 #pragma warning(push,1)
35 #endif
36 
37 // TEMP!!!
38 // Awaiting corresponding functionality in OSL
39 //
40 #define WIN32_LEAN_AND_MEAN
41 #include <windows.h>
42 #include <winbase.h>
43 #include <mmsystem.h>
44 #endif
45 
46 #if defined _MSC_VER
47 #pragma warning(pop)
48 #endif
49 
50 #include <algorithm>
51 #include <limits>
52 
53 namespace canvas {
54 namespace tools {
55 
56 
57 #if defined(WNT)
58 // TODO(Q2): is 0 okay for the failure case here?
getSystemTime()59 double ElapsedTime::getSystemTime()
60 {
61     // TEMP!!!
62     // Awaiting corresponding functionality in OSL
63     //
64 
65     // is there a performance counter available?
66     static bool bTimeSetupDone( false );
67     static bool bPerfTimerAvailable( false );
68     static LONGLONG nPerfCountFreq;
69 
70     // TODO(F1): This _might_ cause problems, as it prevents correct
71     // time handling for very long lifetimes of this class's
72     // surrounding component in memory. When the difference between
73     // current sys time and nInitialCount exceeds IEEE double's
74     // mantissa, time will start to run jerky.
75     static LONGLONG nInitialCount;
76 
77     if( !bTimeSetupDone )
78     {
79         if( QueryPerformanceFrequency(
80                 reinterpret_cast<LARGE_INTEGER *>(&nPerfCountFreq) ) )
81         {
82             // read initial time:
83             QueryPerformanceCounter(
84                 reinterpret_cast<LARGE_INTEGER *>(&nInitialCount) );
85             bPerfTimerAvailable = true;
86         }
87         bTimeSetupDone = true;
88     }
89 
90     if( bPerfTimerAvailable )
91     {
92         LONGLONG nCurrCount;
93         QueryPerformanceCounter(
94             reinterpret_cast<LARGE_INTEGER *>(&nCurrCount) );
95         nCurrCount -= nInitialCount;
96         return double(nCurrCount) / nPerfCountFreq;
97     }
98     else
99     {
100         LONGLONG nCurrTime = timeGetTime();
101         return double(nCurrTime) / 1000.0;
102     }
103 }
104 
105 #else // ! WNT
106 
107 // TODO(Q2): is 0 okay for the failure case here?
108 double ElapsedTime::getSystemTime()
109 {
110     TimeValue aTimeVal;
111     if( osl_getSystemTime( &aTimeVal ) )
112         return ((aTimeVal.Nanosec * 10e-10) + aTimeVal.Seconds);
113     else
114         return 0.0;
115 }
116 
117 #endif
118 
ElapsedTime()119 ElapsedTime::ElapsedTime()
120     : m_pTimeBase(),
121       m_fLastQueriedTime( 0.0 ),
122       m_fStartTime( getSystemTime() ),
123       m_fFrozenTime( 0.0 ),
124       m_bInPauseMode( false ),
125       m_bInHoldMode( false )
126 {
127 }
128 
ElapsedTime(boost::shared_ptr<ElapsedTime> const & pTimeBase)129 ElapsedTime::ElapsedTime(
130     boost::shared_ptr<ElapsedTime> const & pTimeBase )
131     : m_pTimeBase( pTimeBase ),
132       m_fLastQueriedTime( 0.0 ),
133       m_fStartTime( getCurrentTime() ),
134       m_fFrozenTime( 0.0 ),
135       m_bInPauseMode( false ),
136       m_bInHoldMode( false )
137 {
138 }
139 
getTimeBase() const140 boost::shared_ptr<ElapsedTime> const & ElapsedTime::getTimeBase() const
141 {
142     return m_pTimeBase;
143 }
144 
reset()145 void ElapsedTime::reset()
146 {
147     m_fLastQueriedTime = 0.0;
148     m_fStartTime = getCurrentTime();
149     m_fFrozenTime = 0.0;
150     m_bInPauseMode = false;
151     m_bInHoldMode = false;
152 }
153 
adjustTimer(double fOffset,bool)154 void ElapsedTime::adjustTimer( double fOffset, bool /*bLimitToLastQueriedTime*/ )
155 {
156     // to make getElapsedTime() become _larger_, have to reduce
157     // m_fStartTime.
158     m_fStartTime -= fOffset;
159 
160     // also adjust frozen time, this method must _always_ affect the
161     // value returned by getElapsedTime()!
162     if (m_bInHoldMode || m_bInPauseMode)
163         m_fFrozenTime += fOffset;
164 }
165 
getCurrentTime() const166 double ElapsedTime::getCurrentTime() const
167 {
168     return m_pTimeBase.get() == 0
169         ? getSystemTime() : m_pTimeBase->getElapsedTimeImpl();
170 }
171 
getElapsedTime() const172 double ElapsedTime::getElapsedTime() const
173 {
174     m_fLastQueriedTime = getElapsedTimeImpl();
175     return m_fLastQueriedTime;
176 }
177 
getElapsedTimeImpl() const178 double ElapsedTime::getElapsedTimeImpl() const
179 {
180     if (m_bInHoldMode || m_bInPauseMode)
181         return m_fFrozenTime;
182 
183     return getCurrentTime() - m_fStartTime;
184 }
185 
pauseTimer()186 void ElapsedTime::pauseTimer()
187 {
188     m_fFrozenTime = getElapsedTimeImpl();
189     m_bInPauseMode = true;
190 }
191 
continueTimer()192 void ElapsedTime::continueTimer()
193 {
194     m_bInPauseMode = false;
195 
196     // stop pausing, time runs again. Note that
197     // getElapsedTimeImpl() honors hold mode, i.e. a
198     // continueTimer() in hold mode will preserve the latter
199     const double fPauseDuration( getElapsedTimeImpl() - m_fFrozenTime );
200 
201     // adjust start time, such that subsequent getElapsedTime() calls
202     // will virtually start from m_fFrozenTime.
203     m_fStartTime += fPauseDuration;
204 }
205 
holdTimer()206 void ElapsedTime::holdTimer()
207 {
208     // when called during hold mode (e.g. more than once per time
209     // object), the original hold time will be maintained.
210     m_fFrozenTime = getElapsedTimeImpl();
211     m_bInHoldMode = true;
212 }
213 
releaseTimer()214 void ElapsedTime::releaseTimer()
215 {
216     m_bInHoldMode = false;
217 }
218 
219 } // namespace tools
220 } // namespace canvas
221