summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/svg/animation/smil_time.h
blob: 7433a3a1c8578dbeb388628f1050629133c94f83 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
/*
 * Copyright (C) 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_SVG_ANIMATION_SMIL_TIME_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_SVG_ANIMATION_SMIL_TIME_H_

#include <algorithm>
#include <ostream>

#include "base/time/time.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/assertions.h"
#include "third_party/blink/renderer/platform/wtf/hash_traits.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"

namespace blink {

class SMILRepeatCount;
struct SMILInterval;

// SMILTime is used as both a time and time delta in the SMIL animation
// code. It is a small wrapper around TimeDelta that adds two sentinel values
// for SMIL concepts: "indefinite" and "unresolved".
//
// For ordering, the special values have the properties that:
//
//  <finite SMILTime> < SMILTime::Indefinite() < SMILTime::Unresolved()
//
// SMILTime::Earliest() and SMILTime::Latest() are smallest and largest finite
// time values respectively and sort accordingly.
//
// Addition and subtraction follow the semantics defined for computations of
// active duration (https://www.w3.org/TR/SMIL3/smil-timing.html#q78).
class SMILTime {
  DISALLOW_NEW();

 public:
  constexpr SMILTime() = default;

  static constexpr SMILTime Unresolved() { return base::TimeDelta::Max(); }
  static constexpr SMILTime Indefinite() {
    return base::TimeDelta::Max() - base::TimeDelta::FromMicroseconds(1);
  }
  static constexpr SMILTime Latest() {
    return base::TimeDelta::Max() - base::TimeDelta::FromMicroseconds(2);
  }
  static constexpr SMILTime Earliest() { return base::TimeDelta::Min(); }
  static constexpr SMILTime Epsilon() {
    return base::TimeDelta::FromMicroseconds(1);
  }
  static constexpr SMILTime FromSecondsD(double seconds) {
    return std::min(SMILTime(base::TimeDelta::FromSecondsD(seconds)), Latest());
  }
  static constexpr SMILTime FromMicroseconds(int64_t us) {
    return std::min(SMILTime(base::TimeDelta::FromMicroseconds(us)), Latest());
  }

  // Used for computing progress. Don't use for anything else.
  double InternalValueAsDouble() const { return time_.InMicrosecondsF(); }
  double InSecondsF() const { return time_.InSecondsF(); }
  int64_t InMicroseconds() const { return time_.InMicroseconds(); }

  bool IsFinite() const { return *this < Indefinite(); }
  bool IsIndefinite() const { return *this == Indefinite(); }
  bool IsUnresolved() const { return *this == Unresolved(); }

  SMILTime Repeat(SMILRepeatCount repeat_count) const;

  SMILTime operator+(SMILTime other) const {
    if (!IsFinite())
      return time_;
    if (!other.IsFinite())
      return other;
    SMILTime result(time_ + other.time_);
    return result.IsFinite() ? result : Latest();
  }
  SMILTime operator-(SMILTime other) const {
    if (!IsFinite())
      return time_;
    if (!other.IsFinite())
      return other;
    SMILTime result(time_ - other.time_);
    return result.IsFinite() ? result : Latest();
  }
  SMILTime operator-() const { return -time_; }
  // Division and /modulo are used primarily for computing interval
  // progress/repeats.
  int64_t operator/(SMILTime other) const {
    DCHECK(IsFinite());
    DCHECK(other.IsFinite());
    return time_ / other.time_;
  }
  SMILTime operator%(SMILTime other) const {
    DCHECK(IsFinite());
    DCHECK(other.IsFinite());
    return SMILTime(time_ % other.time_);
  }

  bool operator==(SMILTime other) const { return time_ == other.time_; }
  explicit operator bool() const { return IsFinite() && !time_.is_zero(); }
  bool operator!=(SMILTime other) const { return time_ != other.time_; }

  // Ordering of SMILTimes has to follow: finite < indefinite < unresolved. We
  // set this up by assigning consecutive sentinel values for the two latter
  // (see above).
  bool operator>(SMILTime other) const { return time_ > other.time_; }
  bool operator<(SMILTime other) const { return time_ < other.time_; }
  bool operator>=(SMILTime other) const { return time_ >= other.time_; }
  bool operator<=(SMILTime other) const { return time_ <= other.time_; }

 private:
  constexpr SMILTime(base::TimeDelta time) : time_(time) {}

  base::TimeDelta time_;
};

std::ostream& operator<<(std::ostream& os, SMILTime time);

// What generated a SMILTime.
enum class SMILTimeOrigin {
  kAttribute,       // 'begin' / 'end' attribute
  kScript,          // beginElementAt / endElementAt
  kSyncBase,        // Sync-base
  kRepeat,          // Repeat event
  kEvent,           // DOM event
  kLinkActivation,  // Link activation (Click on link referring to timed
                    // element.)
};

class SMILTimeWithOrigin {
  DISALLOW_NEW();

 public:
  SMILTimeWithOrigin(const SMILTime& time, SMILTimeOrigin origin)
      : time_(time), origin_(origin) {}

  const SMILTime& Time() const { return time_; }
  SMILTimeOrigin Origin() const { return origin_; }

 private:
  SMILTime time_;
  SMILTimeOrigin origin_;
};

inline bool operator<(const SMILTimeWithOrigin& a,
                      const SMILTimeWithOrigin& b) {
  return a.Time() < b.Time();
}

// An interval of SMILTimes.
// "...the begin time of the interval is included in the interval, but the end
// time is excluded from the interval."
// (https://www.w3.org/TR/SMIL3/smil-timing.html#q101)
struct SMILInterval {
  DISALLOW_NEW();
  constexpr SMILInterval(const SMILTime& begin, const SMILTime& end)
      : begin(begin), end(end) {}

  static constexpr SMILInterval Unresolved() {
    return {SMILTime::Unresolved(), SMILTime::Unresolved()};
  }

  bool IsResolved() const { return begin.IsFinite(); }
  bool BeginsAfter(SMILTime time) const { return time < begin; }
  bool BeginsBefore(SMILTime time) const { return !BeginsAfter(time); }
  bool EndsAfter(SMILTime time) const {
    DCHECK(IsResolved());
    return time < end;
  }
  bool EndsBefore(SMILTime time) const { return !EndsAfter(time); }
  bool Contains(SMILTime time) const {
    return BeginsBefore(time) && EndsAfter(time);
  }

  SMILTime begin;
  SMILTime end;
};

inline bool operator==(const SMILInterval& a, const SMILInterval& b) {
  return a.begin == b.begin && a.end == b.end;
}

inline bool operator!=(const SMILInterval& a, const SMILInterval& b) {
  return !(a == b);
}

}  // namespace blink

#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_ANIMATION_SMIL_TIME_H_