cfdfdda22a6e1276fc235c431f17c134a649ede5
[WebKit.git] / Source / WTF / wtf / MediaTime.cpp
1 /*
2  * Copyright (C) 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer.
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "MediaTime.h"
31
32 #include <algorithm>
33 #include <wtf/CheckedArithmetic.h>
34 #include <wtf/MathExtras.h>
35
36 using namespace std;
37
38 namespace WTF {
39
40 static int32_t greatestCommonDivisor(int32_t a, int32_t b)
41 {
42     // Euclid's Algorithm
43     int32_t temp = 0;
44     while (b) {
45         temp = b;
46         b = a % b;
47         a = temp;
48     }
49     return a;
50 }
51
52 static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &result)
53 {
54     return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
55 }
56
57 const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
58
59 MediaTime::MediaTime()
60     : m_timeValue(0)
61     , m_timeScale(DefaultTimeScale)
62     , m_timeFlags(Valid)
63 {
64 }
65
66 MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
67     : m_timeValue(value)
68     , m_timeScale(scale)
69     , m_timeFlags(flags)
70 {
71 }
72
73 MediaTime::~MediaTime()
74 {
75 }
76
77 MediaTime::MediaTime(const MediaTime& rhs)
78 {
79     *this = rhs;
80 }
81
82 MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
83 {
84     if (floatTime != floatTime)
85         return invalidTime();
86     if (std::isinf(floatTime))
87         return signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
88     if (floatTime > numeric_limits<int64_t>::max())
89         return positiveInfiniteTime();
90     if (floatTime < numeric_limits<int64_t>::min())
91         return negativeInfiniteTime();
92
93     while (floatTime * timeScale > numeric_limits<int64_t>::max())
94         timeScale /= 2;
95     return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
96 }
97
98 MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
99 {
100     if (doubleTime != doubleTime)
101         return invalidTime();
102     if (std::isinf(doubleTime))
103         return signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
104     if (doubleTime > numeric_limits<int64_t>::max())
105         return positiveInfiniteTime();
106     if (doubleTime < numeric_limits<int64_t>::min())
107         return negativeInfiniteTime();
108
109     while (doubleTime * timeScale > numeric_limits<int64_t>::max())
110         timeScale /= 2;
111     return MediaTime(static_cast<int64_t>(doubleTime * timeScale), timeScale, Valid);
112 }
113
114 float MediaTime::toFloat() const
115 {
116     if (isInvalid() || isIndefinite())
117         return std::numeric_limits<float>::quiet_NaN();
118     if (isPositiveInfinite())
119         return std::numeric_limits<float>::infinity();
120     if (isNegativeInfinite())
121         return -std::numeric_limits<float>::infinity();
122     return static_cast<float>(m_timeValue) / m_timeScale;
123 }
124
125 double MediaTime::toDouble() const
126 {
127     if (isInvalid() || isIndefinite())
128         return std::numeric_limits<double>::quiet_NaN();
129     if (isPositiveInfinite())
130         return std::numeric_limits<double>::infinity();
131     if (isNegativeInfinite())
132         return -std::numeric_limits<double>::infinity();
133     return static_cast<double>(m_timeValue) / m_timeScale;
134 }
135
136 MediaTime& MediaTime::operator=(const MediaTime& rhs)
137 {
138     m_timeValue = rhs.m_timeValue;
139     m_timeScale = rhs.m_timeScale;
140     m_timeFlags = rhs.m_timeFlags;
141     return *this;
142 }
143
144 MediaTime MediaTime::operator+(const MediaTime& rhs) const
145 {
146     if (rhs.isInvalid() || isInvalid())
147         return invalidTime();
148
149     if (rhs.isIndefinite() || isIndefinite())
150         return indefiniteTime();
151
152     if (isPositiveInfinite()) {
153         if (rhs.isNegativeInfinite())
154             return invalidTime();
155         return positiveInfiniteTime();
156     }
157
158     if (isNegativeInfinite()) {
159         if (rhs.isPositiveInfinite())
160             return invalidTime();
161         return negativeInfiniteTime();
162     }
163
164     int32_t commonTimeScale;
165     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
166         commonTimeScale = MaximumTimeScale;
167     MediaTime a = *this;
168     MediaTime b = rhs;
169     a.setTimeScale(commonTimeScale);
170     b.setTimeScale(commonTimeScale);
171     while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
172         if (commonTimeScale == 1)
173             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
174         commonTimeScale /= 2;
175         a.setTimeScale(commonTimeScale);
176         b.setTimeScale(commonTimeScale);
177     }
178     return a;
179 }
180
181 MediaTime MediaTime::operator-(const MediaTime& rhs) const
182 {
183     if (rhs.isInvalid() || isInvalid())
184         return invalidTime();
185
186     if (rhs.isIndefinite() || isIndefinite())
187         return indefiniteTime();
188
189     if (isPositiveInfinite()) {
190         if (rhs.isPositiveInfinite())
191             return invalidTime();
192         return positiveInfiniteTime();
193     }
194
195     if (isNegativeInfinite()) {
196         if (rhs.isNegativeInfinite())
197             return invalidTime();
198         return negativeInfiniteTime();
199     }
200
201     int32_t commonTimeScale;
202     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
203         commonTimeScale = MaximumTimeScale;
204     MediaTime a = *this;
205     MediaTime b = rhs;
206     a.setTimeScale(commonTimeScale);
207     b.setTimeScale(commonTimeScale);
208     while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
209         if (commonTimeScale == 1)
210             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
211         commonTimeScale /= 2;
212         a.setTimeScale(commonTimeScale);
213         b.setTimeScale(commonTimeScale);
214     }
215     return a;
216 }
217
218 bool MediaTime::operator<(const MediaTime& rhs) const
219 {
220     return compare(rhs) == LessThan;
221 }
222
223 bool MediaTime::operator>(const MediaTime& rhs) const
224 {
225     return compare(rhs) == GreaterThan;
226 }
227
228 bool MediaTime::operator==(const MediaTime& rhs) const
229 {
230     return compare(rhs) == EqualTo;
231 }
232
233 bool MediaTime::operator>=(const MediaTime& rhs) const
234 {
235     return compare(rhs) >= EqualTo;
236 }
237
238 bool MediaTime::operator<=(const MediaTime& rhs) const
239 {
240     return compare(rhs) <= EqualTo;
241 }
242
243 MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
244 {
245     if ((isPositiveInfinite() && rhs.isPositiveInfinite())
246         || (isNegativeInfinite() && rhs.isNegativeInfinite())
247         || (isInvalid() && rhs.isInvalid())
248         || (isIndefinite() && rhs.isIndefinite()))
249         return EqualTo;
250
251     if (isInvalid())
252         return GreaterThan;
253
254     if (rhs.isInvalid())
255         return LessThan;
256
257     if (rhs.isNegativeInfinite() || isPositiveInfinite())
258         return GreaterThan;
259
260     if (rhs.isPositiveInfinite() || isNegativeInfinite())
261         return LessThan;
262
263     if (isIndefinite())
264         return GreaterThan;
265
266     if (rhs.isIndefinite())
267         return LessThan;
268
269     int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
270     int64_t lhsWhole = m_timeValue / m_timeScale;
271     if (lhsWhole > rhsWhole)
272         return GreaterThan;
273     if (lhsWhole < rhsWhole)
274         return LessThan;
275
276     int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
277     int64_t lhsRemain = m_timeValue % m_timeScale;
278     int64_t lhsFactor = lhsRemain * rhs.m_timeScale;
279     int64_t rhsFactor = rhsRemain * m_timeScale;
280
281     if (lhsFactor == rhsFactor)
282         return EqualTo;
283     return lhsFactor > rhsFactor ? GreaterThan : LessThan;
284 }
285
286 const MediaTime& MediaTime::zeroTime()
287 {
288     static const MediaTime* time = new MediaTime(0, 1, Valid);
289     return *time;
290 }
291
292 const MediaTime& MediaTime::invalidTime()
293 {
294     static const MediaTime* time = new MediaTime(-1, 1, 0);
295     return *time;
296 }
297
298 const MediaTime& MediaTime::positiveInfiniteTime()
299 {
300     static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
301     return *time;
302 }
303
304 const MediaTime& MediaTime::negativeInfiniteTime()
305 {
306     static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
307     return *time;
308 }
309
310 const MediaTime& MediaTime::indefiniteTime()
311 {
312     static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
313     return *time;
314 }
315
316 void MediaTime::setTimeScale(int32_t timeScale)
317 {
318     if (timeScale == m_timeScale)
319         return;
320     timeScale = std::min(MaximumTimeScale, timeScale);
321     int64_t wholePart = m_timeValue / m_timeScale;
322
323     // If setting the time scale will cause an overflow, divide the
324     // timescale by two until the number will fit, and round the
325     // result.
326     int64_t newWholePart;
327     while (!safeMultiply(wholePart, timeScale, newWholePart))
328         timeScale /= 2;
329
330     int64_t remainder = m_timeValue % m_timeScale;
331     m_timeValue = newWholePart + (remainder * timeScale) / m_timeScale;
332     m_timeScale = timeScale;
333 }
334
335 static int32_t signum(int64_t val)
336 {
337     return (0 < val) - (val < 0);
338 }
339
340 MediaTime abs(const MediaTime& rhs)
341 {
342     if (rhs.isInvalid())
343         return MediaTime::invalidTime();
344     if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
345         return MediaTime::positiveInfiniteTime();
346     MediaTime val = rhs;
347     val.m_timeValue *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
348     return val;
349 }
350
351 }
352