summaryrefslogtreecommitdiffstats
path: root/dom/media/TimeUnits.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/TimeUnits.h')
-rw-r--r--dom/media/TimeUnits.h310
1 files changed, 310 insertions, 0 deletions
diff --git a/dom/media/TimeUnits.h b/dom/media/TimeUnits.h
new file mode 100644
index 000000000..d815b9d40
--- /dev/null
+++ b/dom/media/TimeUnits.h
@@ -0,0 +1,310 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef TIME_UNITS_H
+#define TIME_UNITS_H
+
+#include "Intervals.h"
+#include "mozilla/CheckedInt.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/dom/TimeRanges.h"
+
+namespace mozilla {
+namespace media {
+class TimeIntervals;
+} // namespace media
+} // namespace mozilla
+// CopyChooser specalization for nsTArray
+template<>
+struct nsTArray_CopyChooser<mozilla::media::TimeIntervals>
+{
+ typedef nsTArray_CopyWithConstructors<mozilla::media::TimeIntervals> Type;
+};
+
+namespace mozilla {
+
+// Number of microseconds per second. 1e6.
+static const int64_t USECS_PER_S = 1000000;
+
+// Number of microseconds per millisecond.
+static const int64_t USECS_PER_MS = 1000;
+
+namespace media {
+
+// Number of nanoseconds per second. 1e9.
+static const int64_t NSECS_PER_S = 1000000000;
+
+struct Microseconds {
+ Microseconds()
+ : mValue(0)
+ {}
+
+ explicit Microseconds(int64_t aValue)
+ : mValue(aValue)
+ {}
+
+ double ToSeconds() {
+ return double(mValue) / USECS_PER_S;
+ }
+
+ static Microseconds FromSeconds(double aValue) {
+ MOZ_ASSERT(!IsNaN(aValue));
+
+ double val = aValue * USECS_PER_S;
+ if (val >= double(INT64_MAX)) {
+ return Microseconds(INT64_MAX);
+ } else if (val <= double(INT64_MIN)) {
+ return Microseconds(INT64_MIN);
+ } else {
+ return Microseconds(int64_t(val));
+ }
+ }
+
+ bool operator == (const Microseconds& aOther) const {
+ return mValue == aOther.mValue;
+ }
+ bool operator > (const Microseconds& aOther) const {
+ return mValue > aOther.mValue;
+ }
+ bool operator >= (const Microseconds& aOther) const {
+ return mValue >= aOther.mValue;
+ }
+ bool operator < (const Microseconds& aOther) const {
+ return mValue < aOther.mValue;
+ }
+ bool operator <= (const Microseconds& aOther) const {
+ return mValue <= aOther.mValue;
+ }
+
+ int64_t mValue;
+};
+
+// TimeUnit at present uses a CheckedInt64 as storage.
+// INT64_MAX has the special meaning of being +oo.
+class TimeUnit final {
+public:
+ static TimeUnit FromSeconds(double aValue) {
+ MOZ_ASSERT(!IsNaN(aValue));
+
+ if (mozilla::IsInfinite<double>(aValue)) {
+ return FromInfinity();
+ }
+ // Due to internal double representation, this
+ // operation is not commutative, do not attempt to simplify.
+ double val = (aValue + .0000005) * USECS_PER_S;
+ if (val >= double(INT64_MAX)) {
+ return FromMicroseconds(INT64_MAX);
+ } else if (val <= double(INT64_MIN)) {
+ return FromMicroseconds(INT64_MIN);
+ } else {
+ return FromMicroseconds(int64_t(val));
+ }
+ }
+
+ static TimeUnit FromMicroseconds(int64_t aValue) {
+ return TimeUnit(aValue);
+ }
+
+ static TimeUnit FromMicroseconds(Microseconds aValue) {
+ return TimeUnit(aValue.mValue);
+ }
+
+ static TimeUnit FromNanoseconds(int64_t aValue) {
+ return TimeUnit(aValue / 1000);
+ }
+
+ static TimeUnit FromInfinity() {
+ return TimeUnit(INT64_MAX);
+ }
+
+ static TimeUnit Invalid() {
+ TimeUnit ret;
+ ret.mValue = CheckedInt64(INT64_MAX);
+ // Force an overflow to render the CheckedInt invalid.
+ ret.mValue += 1;
+ return ret;
+ }
+
+ int64_t ToMicroseconds() const {
+ return mValue.value();
+ }
+
+ int64_t ToNanoseconds() const {
+ return mValue.value() * 1000;
+ }
+
+ double ToSeconds() const {
+ if (IsInfinite()) {
+ return PositiveInfinity<double>();
+ }
+ return double(mValue.value()) / USECS_PER_S;
+ }
+
+ bool IsInfinite() const {
+ return mValue.value() == INT64_MAX;
+ }
+
+ bool operator == (const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() == aOther.mValue.value();
+ }
+ bool operator != (const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() != aOther.mValue.value();
+ }
+ bool operator >= (const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() >= aOther.mValue.value();
+ }
+ bool operator > (const TimeUnit& aOther) const {
+ return !(*this <= aOther);
+ }
+ bool operator <= (const TimeUnit& aOther) const {
+ MOZ_ASSERT(IsValid() && aOther.IsValid());
+ return mValue.value() <= aOther.mValue.value();
+ }
+ bool operator < (const TimeUnit& aOther) const {
+ return !(*this >= aOther);
+ }
+ TimeUnit operator + (const TimeUnit& aOther) const {
+ if (IsInfinite() || aOther.IsInfinite()) {
+ return FromInfinity();
+ }
+ return TimeUnit(mValue + aOther.mValue);
+ }
+ TimeUnit operator - (const TimeUnit& aOther) const {
+ if (IsInfinite() && !aOther.IsInfinite()) {
+ return FromInfinity();
+ }
+ MOZ_ASSERT(!IsInfinite() && !aOther.IsInfinite());
+ return TimeUnit(mValue - aOther.mValue);
+ }
+ TimeUnit& operator += (const TimeUnit& aOther) {
+ *this = *this + aOther;
+ return *this;
+ }
+ TimeUnit& operator -= (const TimeUnit& aOther) {
+ *this = *this - aOther;
+ return *this;
+ }
+
+ friend TimeUnit operator* (int aVal, const TimeUnit& aUnit) {
+ return TimeUnit(aUnit.mValue * aVal);
+ }
+ friend TimeUnit operator* (const TimeUnit& aUnit, int aVal) {
+ return TimeUnit(aUnit.mValue * aVal);
+ }
+ friend TimeUnit operator/ (const TimeUnit& aUnit, int aVal) {
+ return TimeUnit(aUnit.mValue / aVal);
+ }
+
+ bool IsValid() const
+ {
+ return mValue.isValid();
+ }
+
+ TimeUnit()
+ : mValue(CheckedInt64(0))
+ {}
+
+ explicit TimeUnit(const Microseconds& aMicroseconds)
+ : mValue(aMicroseconds.mValue)
+ {}
+ TimeUnit& operator = (const Microseconds& aMicroseconds)
+ {
+ mValue = aMicroseconds.mValue;
+ return *this;
+ }
+
+ TimeUnit(const TimeUnit&) = default;
+
+ TimeUnit& operator = (const TimeUnit&) = default;
+
+private:
+ explicit TimeUnit(CheckedInt64 aMicroseconds)
+ : mValue(aMicroseconds)
+ {}
+
+ // Our internal representation is in microseconds.
+ CheckedInt64 mValue;
+};
+
+typedef Maybe<TimeUnit> NullableTimeUnit;
+
+typedef Interval<TimeUnit> TimeInterval;
+
+class TimeIntervals : public IntervalSet<TimeUnit>
+{
+public:
+ typedef IntervalSet<TimeUnit> BaseType;
+
+ // We can't use inherited constructors yet. So we have to duplicate all the
+ // constructors found in IntervalSet base class.
+ // all this could be later replaced with:
+ // using IntervalSet<TimeUnit>::IntervalSet;
+
+ // MOZ_IMPLICIT as we want to enable initialization in the form:
+ // TimeIntervals i = ... like we would do with IntervalSet<T> i = ...
+ MOZ_IMPLICIT TimeIntervals(const BaseType& aOther)
+ : BaseType(aOther)
+ {}
+ MOZ_IMPLICIT TimeIntervals(BaseType&& aOther)
+ : BaseType(Move(aOther))
+ {}
+ explicit TimeIntervals(const BaseType::ElemType& aOther)
+ : BaseType(aOther)
+ {}
+ explicit TimeIntervals(BaseType::ElemType&& aOther)
+ : BaseType(Move(aOther))
+ {}
+
+ static TimeIntervals Invalid()
+ {
+ return TimeIntervals(TimeInterval(TimeUnit::FromMicroseconds(INT64_MIN),
+ TimeUnit::FromMicroseconds(INT64_MIN)));
+ }
+ bool IsInvalid() const
+ {
+ return Length() == 1 && Start(0).ToMicroseconds() == INT64_MIN &&
+ End(0).ToMicroseconds() == INT64_MIN;
+ }
+
+ TimeIntervals() = default;
+
+ // Make TimeIntervals interchangeable with dom::TimeRanges.
+ explicit TimeIntervals(dom::TimeRanges* aRanges)
+ {
+ for (uint32_t i = 0; i < aRanges->Length(); i++) {
+ ErrorResult rv;
+ *this +=
+ TimeInterval(TimeUnit::FromSeconds(aRanges->Start(i, rv)),
+ TimeUnit::FromSeconds(aRanges->End(i, rv)));
+ }
+ }
+ TimeIntervals& operator = (dom::TimeRanges* aRanges)
+ {
+ *this = TimeIntervals(aRanges);
+ return *this;
+ }
+
+ static TimeIntervals FromTimeRanges(dom::TimeRanges* aRanges)
+ {
+ return TimeIntervals(aRanges);
+ }
+
+ void ToTimeRanges(dom::TimeRanges* aRanges) const
+ {
+ for (IndexType i = 0; i < Length(); i++) {
+ aRanges->Add(Start(i).ToSeconds(), End(i).ToSeconds());
+ }
+ }
+};
+
+} // namespace media
+} // namespace mozilla
+
+#endif // TIME_UNITS_H