Support a rational time class for use by media elements.
[WebKit-https.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
35 #if PLATFORM(WIN)
36 // Work around Visual Studio 2008's lack of an isinf or signbit method in STL.
37 namespace std {
38     static bool isinf(double number) { return !_finite(number) && !_isnan(number); }
39     static int signbit(double number) { return number < 0; }
40 }
41 #endif
42
43 using namespace std;
44
45 namespace WTF {
46
47 static int32_t greatestCommonDivisor(int32_t a, int32_t b)
48 {
49     // Euclid's Algorithm
50     int32_t temp = 0;
51     while (b) {
52         temp = b;
53         b = a % b;
54         a = temp;
55     }
56     return a;
57 }
58
59 static int32_t leastCommonMultiple(int32_t a, int32_t b, int32_t &result)
60 {
61     return safeMultiply(a, b / greatestCommonDivisor(a, b), result);
62 }
63
64 const int32_t MediaTime::MaximumTimeScale = 0x7fffffffL;
65
66 MediaTime::MediaTime()
67     : m_timeValue(0)
68     , m_timeScale(DefaultTimeScale)
69     , m_timeFlags(Valid)
70 {
71 }
72
73 MediaTime::MediaTime(int64_t value, int32_t scale, uint32_t flags)
74     : m_timeValue(value)
75     , m_timeScale(scale)
76     , m_timeFlags(flags)
77 {
78 }
79
80 MediaTime::~MediaTime()
81 {
82 }
83
84 MediaTime::MediaTime(const MediaTime& rhs)
85 {
86     *this = rhs;
87 }
88
89 MediaTime MediaTime::createWithFloat(float floatTime, int32_t timeScale)
90 {
91     if (floatTime != floatTime)
92         return invalidTime();
93     if (std::isinf(floatTime))
94         return std::signbit(floatTime) ? negativeInfiniteTime() : positiveInfiniteTime();
95     if (floatTime > numeric_limits<int64_t>::max())
96         return positiveInfiniteTime();
97     if (floatTime < numeric_limits<int64_t>::min())
98         return negativeInfiniteTime();
99
100     while (floatTime * timeScale > numeric_limits<int64_t>::max())
101         timeScale /= 2;
102     return MediaTime(static_cast<int64_t>(floatTime * timeScale), timeScale, Valid);
103 }
104
105 MediaTime MediaTime::createWithDouble(double doubleTime, int32_t timeScale)
106 {
107     if (doubleTime != doubleTime)
108         return invalidTime();
109     if (std::isinf(doubleTime))
110         return std::signbit(doubleTime) ? negativeInfiniteTime() : positiveInfiniteTime();
111     if (doubleTime > numeric_limits<int64_t>::max())
112         return positiveInfiniteTime();
113     if (doubleTime < numeric_limits<int64_t>::min())
114         return negativeInfiniteTime();
115
116     while (doubleTime * timeScale > numeric_limits<int64_t>::max())
117         timeScale /= 2;
118     return MediaTime(static_cast<int64_t>(doubleTime * timeScale), timeScale, Valid);
119 }
120
121 float MediaTime::toFloat() const
122 {
123     if (isInvalid() || isIndefinite())
124         return std::numeric_limits<float>::quiet_NaN();
125     if (isPositiveInfinite())
126         return std::numeric_limits<float>::infinity();
127     if (isNegativeInfinite())
128         return -std::numeric_limits<float>::infinity();
129     return static_cast<float>(m_timeValue) / m_timeScale;
130 }
131
132 double MediaTime::toDouble() const
133 {
134     if (isInvalid() || isIndefinite())
135         return std::numeric_limits<double>::quiet_NaN();
136     if (isPositiveInfinite())
137         return std::numeric_limits<double>::infinity();
138     if (isNegativeInfinite())
139         return -std::numeric_limits<double>::infinity();
140     return static_cast<double>(m_timeValue) / m_timeScale;
141 }
142
143 MediaTime& MediaTime::operator=(const MediaTime& rhs)
144 {
145     m_timeValue = rhs.m_timeValue;
146     m_timeScale = rhs.m_timeScale;
147     m_timeFlags = rhs.m_timeFlags;
148     return *this;
149 }
150
151 MediaTime MediaTime::operator+(const MediaTime& rhs) const
152 {
153     if (rhs.isInvalid() || isInvalid())
154         return invalidTime();
155
156     if (rhs.isIndefinite() || isIndefinite())
157         return indefiniteTime();
158
159     if (isPositiveInfinite()) {
160         if (rhs.isNegativeInfinite())
161             return invalidTime();
162         return positiveInfiniteTime();
163     }
164
165     if (isNegativeInfinite()) {
166         if (rhs.isPositiveInfinite())
167             return invalidTime();
168         return negativeInfiniteTime();
169     }
170
171     int32_t commonTimeScale;
172     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
173         commonTimeScale = MaximumTimeScale;
174     MediaTime a = *this;
175     MediaTime b = rhs;
176     a.setTimeScale(commonTimeScale);
177     b.setTimeScale(commonTimeScale);
178     while (!safeAdd(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
179         if (commonTimeScale == 1)
180             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
181         commonTimeScale /= 2;
182         a.setTimeScale(commonTimeScale);
183         b.setTimeScale(commonTimeScale);
184     }
185     return a;
186 }
187
188 MediaTime MediaTime::operator-(const MediaTime& rhs) const
189 {
190     if (rhs.isInvalid() || isInvalid())
191         return invalidTime();
192
193     if (rhs.isIndefinite() || isIndefinite())
194         return indefiniteTime();
195
196     if (isPositiveInfinite()) {
197         if (rhs.isPositiveInfinite())
198             return invalidTime();
199         return positiveInfiniteTime();
200     }
201
202     if (isNegativeInfinite()) {
203         if (rhs.isNegativeInfinite())
204             return invalidTime();
205         return negativeInfiniteTime();
206     }
207
208     int32_t commonTimeScale;
209     if (!leastCommonMultiple(this->m_timeScale, rhs.m_timeScale, commonTimeScale) || commonTimeScale > MaximumTimeScale)
210         commonTimeScale = MaximumTimeScale;
211     MediaTime a = *this;
212     MediaTime b = rhs;
213     a.setTimeScale(commonTimeScale);
214     b.setTimeScale(commonTimeScale);
215     while (!safeSub(a.m_timeValue, b.m_timeValue, a.m_timeValue)) {
216         if (commonTimeScale == 1)
217             return a.m_timeValue > 0 ? positiveInfiniteTime() : negativeInfiniteTime();
218         commonTimeScale /= 2;
219         a.setTimeScale(commonTimeScale);
220         b.setTimeScale(commonTimeScale);
221     }
222     return a;
223 }
224
225 bool MediaTime::operator<(const MediaTime& rhs) const
226 {
227     return compare(rhs) == LessThan;
228 }
229
230 bool MediaTime::operator>(const MediaTime& rhs) const
231 {
232     return compare(rhs) == GreaterThan;
233 }
234
235 bool MediaTime::operator==(const MediaTime& rhs) const
236 {
237     return compare(rhs) == EqualTo;
238 }
239
240 bool MediaTime::operator>=(const MediaTime& rhs) const
241 {
242     return compare(rhs) >= EqualTo;
243 }
244
245 bool MediaTime::operator<=(const MediaTime& rhs) const
246 {
247     return compare(rhs) <= EqualTo;
248 }
249
250 MediaTime::ComparisonFlags MediaTime::compare(const MediaTime& rhs) const
251 {
252     if ((isPositiveInfinite() && rhs.isPositiveInfinite())
253         || (isNegativeInfinite() && rhs.isNegativeInfinite())
254         || (isInvalid() && rhs.isInvalid())
255         || (isIndefinite() && rhs.isIndefinite()))
256         return EqualTo;
257
258     if (isInvalid())
259         return GreaterThan;
260
261     if (rhs.isInvalid())
262         return LessThan;
263
264     if (rhs.isNegativeInfinite() || isPositiveInfinite())
265         return GreaterThan;
266
267     if (rhs.isPositiveInfinite() || isNegativeInfinite())
268         return LessThan;
269
270     if (isIndefinite())
271         return GreaterThan;
272
273     if (rhs.isIndefinite())
274         return LessThan;
275
276     int64_t rhsWhole = rhs.m_timeValue / rhs.m_timeScale;
277     int64_t lhsWhole = m_timeValue / m_timeScale;
278     if (lhsWhole > rhsWhole)
279         return GreaterThan;
280     if (lhsWhole < rhsWhole)
281         return LessThan;
282
283     int64_t rhsRemain = rhs.m_timeValue % rhs.m_timeScale;
284     int64_t lhsRemain = m_timeValue % m_timeScale;
285     int64_t lhsFactor = lhsRemain * rhs.m_timeScale;
286     int64_t rhsFactor = rhsRemain * m_timeScale;
287
288     if (lhsFactor == rhsFactor)
289         return EqualTo;
290     return lhsFactor > rhsFactor ? GreaterThan : LessThan;
291 }
292
293 const MediaTime& MediaTime::zeroTime()
294 {
295     static const MediaTime* time = new MediaTime(0, 1, Valid);
296     return *time;
297 }
298
299 const MediaTime& MediaTime::invalidTime()
300 {
301     static const MediaTime* time = new MediaTime(-1, 1, 0);
302     return *time;
303 }
304
305 const MediaTime& MediaTime::positiveInfiniteTime()
306 {
307     static const MediaTime* time = new MediaTime(0, 1, PositiveInfinite | Valid);
308     return *time;
309 }
310
311 const MediaTime& MediaTime::negativeInfiniteTime()
312 {
313     static const MediaTime* time = new MediaTime(-1, 1, NegativeInfinite | Valid);
314     return *time;
315 }
316
317 const MediaTime& MediaTime::indefiniteTime()
318 {
319     static const MediaTime* time = new MediaTime(0, 1, Indefinite | Valid);
320     return *time;
321 }
322
323 void MediaTime::setTimeScale(int32_t timeScale)
324 {
325     if (timeScale == m_timeScale)
326         return;
327     timeScale = std::min(MaximumTimeScale, timeScale);
328     int64_t wholePart = m_timeValue / m_timeScale;
329
330     // If setting the time scale will cause an overflow, divide the
331     // timescale by two until the number will fit, and round the
332     // result.
333     int64_t newWholePart;
334     while (!safeMultiply(wholePart, timeScale, newWholePart))
335         timeScale /= 2;
336
337     int64_t remainder = m_timeValue % m_timeScale;
338     m_timeValue = newWholePart + (remainder * timeScale) / m_timeScale;
339     m_timeScale = timeScale;
340 }
341
342 static int32_t signum(int64_t val)
343 {
344     return (0 < val) - (val < 0);
345 }
346
347 MediaTime abs(const MediaTime& rhs)
348 {
349     if (rhs.isInvalid())
350         return MediaTime::invalidTime();
351     if (rhs.isNegativeInfinite() || rhs.isPositiveInfinite())
352         return MediaTime::positiveInfiniteTime();
353     MediaTime val = rhs;
354     val.m_timeValue *= signum(rhs.m_timeScale) * signum(rhs.m_timeValue);
355     return val;
356 }
357
358 }
359